EntityAdded Event

Summary

The EntityAdded event fires during database upgrade when a new table is detected in the EF Core model that does not exist in the current database. Use it to seed initial data into the new table or migrate data from other tables.

When does it fire?

EntityAdded fires when the schema comparison detects a table in the new EF Core model that does not exist in the live database. The subscriber runs after the table has been created, so you can insert data into it.

Schema comparison → New table detected → Table created → EntityAdded subscribers

Syntax

[EntityAdded(typeof(EntityType))]
public void MethodName(EntityAddedEventArgs args)
{
    args.UpgradeScript("SQL script here");
}

Attribute

Parameter Type Description
entityType Type The entity type being added (used as typeof(Entity))

Event Args (EntityAddedEventArgs)

Property/Method Description
TableName The database table name that was created
UpgradeScript(sql) Adds a SQL script to execute during the upgrade
ReadFromDatabase(sql) Reads data from the database to help generate migration scripts

Scenarios

1. Seeding initial data into a new table

When a new Category entity is added, seed it with default categories.

public class DataBaseUpgrade
{
    [EntityAdded(typeof(Category))]
    public void SeedDefaultCategories(EntityAddedEventArgs args)
    {
        args.UpgradeScript($@"
            INSERT INTO ""{args.TableName}"" (""Guid"", ""Name"", ""SortOrder"")
            VALUES
                (gen_random_uuid(), 'General', 1),
                (gen_random_uuid(), 'Premium', 2);");
    }
}

2. Migrating data from an existing table into a new one

When a new ProductVariant table replaces inline variant columns on Product, migrate existing data.

public class DataBaseUpgrade
{
    [EntityAdded(typeof(ProductVariant))]
    public void MigrateVariantData(EntityAddedEventArgs args)
    {
        var products = args.ReadFromDatabase(
            """SELECT "Guid", "VariantName", "VariantSku" FROM "Product" WHERE "VariantName" IS NOT NULL""");

        foreach (System.Data.DataRow row in products.Rows)
        {
            var productGuid = row["Guid"];
            var name = row["VariantName"];
            var sku = row["VariantSku"];

            args.UpgradeScript($@"
                INSERT INTO ""{args.TableName}"" (""Guid"", ""ProductGuid"", ""Name"", ""Sku"")
                VALUES (gen_random_uuid(), '{productGuid}', '{name}', '{sku}');");
        }
    }
}

3. Copying configuration data from a legacy table

When a new settings table is introduced, copy configuration from the old structure.

public class DataBaseUpgrade
{
    [EntityAdded(typeof(CompanySetting))]
    public void MigrateFromLegacySettings(EntityAddedEventArgs args)
    {
        args.UpgradeScript($@"
            INSERT INTO ""{args.TableName}"" (""Guid"", ""Key"", ""Value"")
            SELECT gen_random_uuid(), ""SettingKey"", ""SettingValue""
            FROM ""LegacyConfig""
            WHERE ""SettingKey"" IS NOT NULL;");
    }
}

Notes

  • The [EntityAdded] attribute can be applied multiple times to the same method if the same logic applies to multiple new entities.
  • The table has already been created by the time the subscriber runs, so you can INSERT data into it.
  • Use ReadFromDatabase to read data from existing tables that need to be migrated into the new table.
  • EntityAdded is typically used together with EntityDeleted when replacing one table with another.