Table of Contents


Magentrix Trigger Lifecycle & Code Structure

Magentrix Trigger Lifecycle & Code Structure

 

In Magentrix, triggers are used to execute custom logic before or after changes are made to records in the system. This guide explains the structure and lifecycle of a trigger using a sample trigger class: LeadTrigger.


Trigger Structure

 

Every Magentrix trigger inherits from ActiveTrigger<T>, where T is the entity type (e.g., Lead, Account, etc.). The primary method you override is Execute(TransactionContext<T> trigger), which receives a TransactionContext containing the list of records involved in the operation and transaction metadata.

public class LeadTrigger : ActiveTrigger<Lead>
{
    public override void Execute(TransactionContext<Lead> trigger)
    {
        // Logic goes here
    }
}

Trigger Lifecycle Overview

Triggers in Magentrix are executed in two phases:

1. Before Events (trigger.IsBefore)

These events occur before the database transaction is committed. They allow you to validate, modify, or prevent data changes. Only native Magentrix entities support before-triggers.

 

  • Use Cases:

    • Validation

    • Data transformation

    • Logging

    • Blocking unwanted changes

 

a. Before Insert

if (trigger.IsInsert)
{
    foreach (var rec in trigger.Records)
    {
        SystemInfo.Debug($"[Before Insert] Creating record: {rec.New.Name}");
    }
}
  • rec.New is populated.

  • rec.New.Id is not yet assigned.

 

b. Before Update

if (trigger.IsUpdate)
{
    foreach (var rec in trigger.Records)
    {
        SystemInfo.Debug($"[Before Update] New: {rec.New.Name} | Old: {rec.Old.Name}");
    }
}
  • rec.New = updated values

  • rec.Old = original values

 

c. Before Delete

if (trigger.IsDelete)
{
    foreach (var rec in trigger.Records)
    {
        SystemInfo.Debug($"[Before Delete] Deleting record: {rec.Old.Id}");
    }
}
  • Only rec.Old is populated.

  • rec.New is always null.


2. After Events (trigger.IsAfter)

These events execute after the transaction is committed. They are available for both native and CRM-synced records.

  • Use Cases:

    • External system integration

    • Sending notifications

    • Audit logging

    • Triggering follow-up processes

a. After Insert

if (trigger.IsInsert)
{
    foreach (var rec in trigger.Records)
    {
        SystemInfo.Debug($"[After Insert] Created record: {rec.New.Id}");
    }
}
  • rec.New.Id is now available.

 

b. After Update

if (trigger.IsUpdate)
{
    foreach (var rec in trigger.Records)
    {
        SystemInfo.Debug($"[After Update] New: {rec.New.Name} | Old: {rec.Old.Name}");
    }
}
  • Useful for logging or syncing changes to external systems.

 

c. After Delete (Not available for CRM entities)

if (trigger.IsDelete)
{
    foreach (var rec in trigger.Records)
    {
        SystemInfo.Debug($"[After Delete] Deleted record: {rec.Old.Id}");
    }
}
  • Only rec.Old is available.


Here is the complete Sample of the Life Cycle

public class LeadTrigger : ActiveTrigger<Lead>
{
    public override void Execute(TransactionContext<Lead> trigger)
    {
        if (trigger.IsBefore)
        {
            // This block is only called for Magentrix native entities
            // It allows actions before a record is committed to the database

            if (trigger.IsDelete)
            {
                // This runs before deleting a native record
                // Only rec.Old is populated (rec.New is always null)
                foreach (var rec in trigger.Records)
                {
                    SystemInfo.Debug($"[Before Delete] Deleting record: {rec.Old.Id}");
                }
            }

            if (trigger.IsInsert)
            {
                // Runs before inserting a native record
                // Only rec.New is populated (rec.New.Id is empty at this point)
                foreach (var rec in trigger.Records)
                {
                    SystemInfo.Debug($"[Before Insert] Creating record: {rec.New.Name}");
                }
            }

            if (trigger.IsUpdate)
            {
                // Runs before updating a native record
                // rec.Old = original record, rec.New = updated values
                foreach (var rec in trigger.Records)
                {
                    SystemInfo.Debug($"[Before Update] New: {rec.New.Name} | Old: {rec.Old.Name}");
                }
            }
        }

        if (trigger.IsAfter)
        {
            // This block runs after the transaction has been committed
            // It applies to both native and CRM-synced entities

            if (trigger.IsDelete)
            {
                // Runs after deleting a native record
                foreach (var rec in trigger.Records)
                {
                    SystemInfo.Debug($"[After Delete] Deleted record: {rec.Old.Id}");
                }
            }

            if (trigger.IsInsert)
            {
                // Runs after inserting a native or CRM record
                // rec.New.Id is now available
                foreach (var rec in trigger.Records)
                {
                    SystemInfo.Debug($"[After Insert] Created record: {rec.New.Id}");
                }
            }

            if (trigger.IsUpdate)
            {
                // Runs after updating a native or CRM record
                foreach (var rec in trigger.Records)
                {
                    SystemInfo.Debug($"[After Update] New: {rec.New.Name} | Old: {rec.Old.Name}");
                }
            }
        }
    }
}

Here is a Sample Code For this Video

 

public class HotDealTrigger : ActiveTrigger<Lead>
{
    public override void Execute(TransactionContext<Lead> trigger)
    {
        if (trigger.IsAfter)
        {
            if (trigger.IsInsert || trigger.IsUpdate)
            {
                var accountIds = trigger.Records.Where (a => !string.IsNullOrEmpty(a.New.PartnerAccountId)).Select(a => a.New.PartnerAccountId).ToList();
                if (accountIds.Count > 0)
                {
                    var accounts = Database.Query<Account>(a => accountIds.Contains(a.Id)).ToListAsAdmin();
                    var ownerIds = accounts.Select(a => a.OwnerId).ToList();
                    var owners = Database.Query<User>(a => ownerIds.Contains(a.Id)).ToListAsAdmin();
                    foreach (var rec in trigger.Records.Where(a => !string.IsNullOrEmpty(a.New.PartnerAccountId)))
                    {
                        var account = accounts.FirstOrDefault(a => a.Id == rec.New.PartnerAccountId);
                        if (account == null) continue;
                        var owner = owners.FirstOrDefault(a => a.Id == account.OwnerId);
                        if (owner == null || !string.IsNullOrEmpty(owner.MobilePhone)) continue;
                        var twilio = new Messaging.Twilio("your_config_name");
                        twilio.SendSMS(owner.MobilePhone, $"You have a hot deal: {SystemInfo.Company.OrgURL}/{rec.New.Id}");
                    }
                }
            }
        }
    }
}

Key Concepts

Concept

Description

trigger.IsBefore

Executes before database changes. Only for native entities.

trigger.IsAfter

Executes after database changes. Works for both native and CRM entities.

trigger.IsInsert

Indicates a create operation.

trigger.IsUpdate

Indicates an update operation.

trigger.IsDelete

Indicates a delete operation. (Not supported for CRM entities)

rec.New

Represents the new state of the record (for insert/update).

rec.Old

Represents the original state of the record (for update/delete).

 


Example Use Cases

Trigger Phase

Operation

Common Use Cases

Before

Insert

Default value population, validation logic

Before

Update

Field-level security, change logging

Before

Delete

Preventing deletion of critical records

After

Insert

Notifications, integrations, audit trails

After

Update

Sync with external tools, workflow triggers

After

Delete

Cleanup tasks, external system updates

 


Best Practices

  • Use Before triggers for validation and data manipulation.

  • Use After triggers for integrations, logging, and asynchronous workflows.

  • Always check both trigger.IsBefore/IsAfter and IsInsert/Update/Delete to avoid unintended behavior.

  • Be mindful of system performance—avoid heavy operations inside triggers.