Skip to content

Settings.UpdateColumn

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

Settings.UpdateColumn

Runs your code once for every column, so you can rename a property, change its type, hide it, or attach an attribute.

Type Action<Column, Table, List<EnumDefinition>, List<JsonColumnMapping>>
Default Calls the four built-in Settings.Apply* helpers and nothing else
Applies to EF 6 and EF Core
Databases All
In Database.tt? Yes, with a long block of commented-out examples

What it does

This is the main hook for reshaping the generated model. The generator reads your schema, then for each column calls this delegate with:

Parameter What it is
column The column being processed. Change its fields to change the generated property
table The table the column belongs to, so you can apply a rule to one table only
enumDefinitions The enum mappings collected from Settings.AddEnumDefinitions
jsonColumnMappings The JSON mappings collected from Settings.AddJsonColumnMappings

You mutate column in place; there is no return value. It is called after the schema has been read and before any code is written, so anything you change here is what gets generated.

The fields you will use most

Field Type Effect
NameHumanCase string The C# property name. Assign to rename it
DbName string The real column name. Read-only in practice - it is what maps to the database
PropertyType string The C# type, as text: "int", "string", "MyEnum"
Hidden bool true generates nothing at all for this column
ExistsInBaseClass bool true skips the property because a base class already declares it
Attributes List<string> Attributes to put above the property, brackets included
IsConcurrencyToken bool Marks the column as a concurrency token
IsPartial bool Emits a partial property for you to implement by hand (C# 13+)
OverrideModifier bool Adds override to the property

ExtendedProperties is a case-insensitive dictionary of the column's database comments and extended properties, which is how you drive generation from the database itself. See Extended Property Names Feature.

Do not drop the built-in helpers

The shipped Database.tt ends the delegate with four calls:

Settings.ApplyJsonPropertyNameAttribute(column);
Settings.ApplyJsonColumnMappings(column, table, jsonColumnMappings);
Settings.ApplyDataAnnotations(column);
Settings.ApplyEnumTypeReplacement(column, table, enumDefinitions);

These are what make Settings.UseDataAnnotations, Settings.AddJsonColumnMappings and Settings.AddEnumDefinitions actually do anything. If you replace the whole delegate and forget them, those three settings silently stop working - nothing errors, the attributes just never appear. Add your rules above the helpers and leave them in place.

Example

Two rules: rename ProductId to Id, and keep the Notes column out of the model.

Settings.UpdateColumn = delegate(Column column, Table table, List<EnumDefinition> enumDefinitions, List<JsonColumnMapping> jsonColumnMappings)
{
    // Rename a primary key called <Table>Id to just Id
    if (column.IsPrimaryKey && column.NameHumanCase == table.NameHumanCase + "Id")
        column.NameHumanCase = "Id";

    // Keep an internal column out of the model entirely
    if (column.NameHumanCase == "Notes")
        column.Hidden = true;

    Settings.ApplyDataAnnotations(column);
};

Before

    // Product
    public class Product
    {
        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;
        }
    }

After

    // Product
    public class Product
    {
        public int Id { get; set; } // ProductId (Primary key)
        public string ProductName { get; set; } // ProductName (length: 100)
        public decimal UnitPrice { get; set; } // UnitPrice
        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;
        }
    }

ProductId became Id, and Notes is gone. Note the comment on the renamed property still says // ProductId - that is deliberate, so you can always see which database column a property came from.

When to use it

  • Renaming to a house style. Stripping a fld_ prefix, or turning every <Table>Id primary key into Id.
  • Hiding columns. Audit columns you never read, or a password_hash that should not be on an entity at all.
  • Base classes. Set ExistsInBaseClass = true on CreatedBy/CreatedOn and give the table a base class in Settings.UpdateTable that declares them once.
  • Attributes. Anything from [JsonIgnore] to your own validation attributes.
  • Overriding a type. Force a tinyint to int, or a SQLite INTEGER from long to int.

Gotchas

Renaming here does not change the database mapping, which is the point. NameHumanCase is the C# name; HasColumnName in the configuration still uses DbName. That is why renaming is safe.

Two columns can collide. Rename ProductId to Id in a table that already has an Id column and you generate a class with two Id properties, which will not compile. The generator does not check for you.

Hidden on a non-nullable column without a default will break inserts. The column is gone from the model, so EF never supplies a value, and the database rejects the row. Hide only nullable columns or columns with a database default.

It runs for every column of every table, including ones you filtered out earlier in the run, so guard your rules with a check on table.NameHumanCase rather than assuming a name is unique.

column.PropertyType is a string, not a Type. Assign "int?" for a nullable int - there is no type-checking, so a typo becomes a compiler error in the generated file.

See also

Clone this wiki locally