Skip to content

Data Annotations

Simon Hughes edited this page Mar 20, 2026 · 5 revisions

Automatic Data Annotations

Set Settings.UseDataAnnotations = true in Database.tt to automatically add standard data annotation attributes to generated POCO properties:

Settings.UseDataAnnotations = true;

Automatically generated annotations:

Scenario Generated Attribute
Primary key column [Key, Column(Order = n)]
Non-nullable, non-computed column (string) [Required(AllowEmptyStrings = true)] or [Required]
String column with max length [MaxLength(n)] and [StringLength(n)]
Max-length string column (nvarchar(max)) [MaxLength]
Row version / timestamp column [Timestamp, ConcurrencyCheck]
All columns [Display(Name = "...")]
SQL Server 2025 vector column [Column(TypeName = "vector(n)")]

Custom Annotations via UpdateColumn

For more control, add custom attributes directly in Settings.UpdateColumn:

Settings.UpdateColumn = delegate(Column column, Table table, List<EnumDefinition> enumDefinitions, List<JsonColumnMapping> jsonColumnMappings)
{
    // Add Display attribute
    column.Attributes.Add($"[Display(Name = \"{column.DisplayName}\")]");

    // Add key attribute to primary keys
    if (column.IsPrimaryKey)
        column.Attributes.Add("[Key]");

    // Add a custom attribute to a specific table's primary key
    if (column.IsPrimaryKey && table.NameHumanCase.Equals("Order", StringComparison.InvariantCultureIgnoreCase))
        column.Attributes.Add("[CustomOrderKey]");

    // Mark concurrency token
    if (table.NameHumanCase == "Product" && column.NameHumanCase == "RowVersion")
        column.IsConcurrencyToken = true;

    // Apply built-in helpers
    Settings.ApplyDataAnnotations(column);
};

Adding Required Namespaces

If you use annotation types that aren't in the default namespaces, add them in Database.tt:

Settings.AdditionalNamespaces = new List<string>
{
    "System.ComponentModel.DataAnnotations",
    "System.ComponentModel.DataAnnotations.Schema"
};

These namespaces are included by default when UseDataAnnotations = true.

[JsonPropertyName] from Extended Properties

You can automatically add [JsonPropertyName] attributes to properties using SQL Server extended properties. Set the extended property JsonPropertyName on a column in SQL Server:

EXEC sp_addextendedproperty
    @name  = N'JsonPropertyName', @value = N'id',
    @level0type = N'SCHEMA', @level0name = N'dbo',
    @level1type = N'TABLE',  @level1name = N'YourTable',
    @level2type = N'COLUMN', @level2name = N'SystemId'

The generator automatically calls Settings.ApplyJsonPropertyNameAttribute(column) and will add:

  • [JsonPropertyName("id")] for EF Core 8+ (using System.Text.Json.Serialization)
  • [JsonProperty("id")] for EF 6 (using Newtonsoft.Json)

See Extended Property Names Feature for more.

[JsonIgnore] on Navigation Properties

To exclude reverse navigation and foreign key properties from JSON serialization:

Settings.AdditionalReverseNavigationsDataAnnotations = new string[]
{
    "JsonIgnore"  // Adds [JsonIgnore] to all reverse navigation properties
};

Settings.AdditionalForeignKeysDataAnnotations = new string[]
{
    "JsonIgnore"  // Adds [JsonIgnore] to all foreign key properties
};

Settings.AdditionalNamespaces = new List<string>
{
    "Newtonsoft.Json"  // Or "System.Text.Json.Serialization" for .NET built-in
};

For finer-grained control, use Settings.ForeignKeyAnnotationsProcessing — see Settings Callbacks.

Clone this wiki locally