Skip to content

Settings.UpdateTable

Simon Hughes edited this page Aug 30, 2026 · 1 revision

Settings.UpdateTable

Runs your code once for every table and view after naming, so you can attach a base class, add class-level attributes, or drop the table entirely.

Type Action<Table>
Default Does nothing
Applies to EF 6 and EF Core
Databases All
In Database.tt? Yes, with commented-out examples

What it does

Where Settings.TableRename runs before naming, this runs after it, so the table arrives fully formed: NameHumanCase is the final class name, Columns is populated, and the schema is known. It is called just before Settings.UpdateColumn runs for that table's columns.

You mutate the Table in place. The fields worth knowing:

Field Type Effect
NameHumanCase string The C# class name. Assign to rename
DbName string The database table name, for matching on
Schema.DbName string The schema, for matching on
BaseClasses string Written straight after the class name, colon included: " : IAuditable"
Attributes List<string> Class-level attributes, brackets included
AdditionalComment string An extra comment above the class
Columns List<Column> Every column, so you can decide based on what the table contains
HasPrimaryKey bool Useful for spotting views and junction tables
RemoveTable bool true drops the table from generation entirely
IsView bool Distinguishes a view from a table
PluralNameOverride string Overrides just the DbSet name, leaving the class alone
DbSetModifier string The access modifier on the DbSet property, "public" by default

Example

Giving Product a base interface and an attribute:

Settings.UpdateTable = delegate(Table table)
{
    if (table.NameHumanCase == "Product")
    {
        table.BaseClasses = " : IAuditable";
        table.Attributes.Add("[Serializable]");
    }
};

Before

public class Product

After

    // Product
    [Serializable]
    public class Product : IAuditable
    {
        public int ProductId { get; set; } // ProductId (Primary key)
        public string ProductName { get; set; } // ProductName (length: 100)
        public decimal UnitPrice { get; set; } // UnitPrice
        public string Notes { get; set; } // Notes
        public int CategoryId { get; set; } // CategoryId
        public string DisplayLabel { get; private set; } // DisplayLabel (length: 150)

        // Foreign keys

        /// <summary>
        /// Parent Category pointed by [Product].([CategoryId]) (FK_Product_Category)
        /// </summary>
        public Category Category { get; set; } // FK_Product_Category

        public Product()
        {
            UnitPrice = 0m;
        }
    }

Note the leading space and colon in " : IAuditable". The value is written verbatim after the class name, so the punctuation is yours to supply.

When to use it

A base class chosen by what the table contains. The most useful pattern by far - the rule lives in one place and picks up new tables automatically:

Settings.UpdateTable = delegate(Table table)
{
    var audit = new[] { "createdby", "createdon", "modifiedby", "modifiedon" };
    if (audit.All(a => table.Columns.Any(c => c.NameHumanCase.ToLower() == a)))
        table.BaseClasses = " : AuditableEntity";
};

Pair it with column.ExistsInBaseClass = true in Settings.UpdateColumn so those four columns are declared once on the base class rather than on every entity.

Dropping a table you cannot filter out. RemoveTable = true is the late escape hatch for a table that has to be read - because something else has a foreign key to it - but must not be generated.

Marking entities for a serialiser or a validator, with [Serializable], [DataContract] or your own.

Gotchas

BaseClasses is a raw string, not a list. Setting it twice overwrites; to add a second interface, append to it. And the generator does not check the type exists - a typo becomes a compiler error in the generated file.

RemoveTable does not remove the relationships pointing at it. Other entities may still have navigation properties expecting the class you just dropped. Prefer a filter where you can, and use RemoveTable only when the table has to be read for something else's sake.

It runs for views too. Check table.IsView before applying a rule that only makes sense for tables. For views specifically, Settings.ViewProcessing runs later and is the place to declare which columns form the key.

Renaming here is late. NameHumanCase is assignable, but the reverse navigation properties on other tables have not necessarily been named yet, and the schema prefix has already been applied. For a rename that propagates cleanly, use Settings.TableRename.

See also

Clone this wiki locally