-
Notifications
You must be signed in to change notification settings - Fork 226
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 |
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.
| 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.
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.
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);
}; // 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;
}
} // 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.
-
Renaming to a house style. Stripping a
fld_prefix, or turning every<Table>Idprimary key intoId. -
Hiding columns. Audit columns you never read, or a
password_hashthat should not be on an entity at all. -
Base classes. Set
ExistsInBaseClass = trueonCreatedBy/CreatedOnand give the table a base class inSettings.UpdateTablethat declares them once. -
Attributes. Anything from
[JsonIgnore]to your own validation attributes. -
Overriding a type. Force a
tinyinttoint, or a SQLiteINTEGERfromlongtoint.
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.
- Settings Callbacks - the other delegates, and where this one sits in the pipeline
- Settings.UpdateTable - the same idea, one level up
- Data Annotations
- Extended Property Names Feature
-
Partial Properties - what
column.IsPartialis for - Settings Reference
- Settings A-Z - every setting, with a page each
- Common Settings Types Explained
- Settings Callbacks
- Settings runtime values and helpers
- Filtering
- Full Control Over the Generated Code
- Enum Generation from Table Data
- Owned Entities
- JSON column support
- Global Query Filters
- Extended Property Names Feature
- Partial Properties
- File-Scoped Namespaces
- Data Annotations
- Spatial Types
- HierarchyId
- RowVersion and TimeStamp columns
- Lazy Loading
- Stored proc result sets
- Custom File-Based Templates
- Extra entities via partial classes
- INotifyPropertyChanged
- Syntax colour for T4