Skip to content

Settings.AddOwnedEntityMappings

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

Settings.AddOwnedEntityMappings

Groups columns that share a prefix into an EF Core owned entity, so BillingAddress_Street and its neighbours become customer.BillingAddress.Street.

Type Action<List<OwnedEntityMapping>>
Default Adds nothing
Applies to EF Core only. EF 6 complex types are not generated
Databases All
In Database.tt? Yes, with commented-out examples

What it does

Databases often flatten a value object across several columns:

CREATE TABLE dbo.Customer
(
    CustomerId              int           NOT NULL IDENTITY(1, 1),
    BillingAddress_Street   nvarchar(100) NOT NULL,
    BillingAddress_City     nvarchar(60)  NOT NULL,
    BillingAddress_Postcode nvarchar(10)  NOT NULL,
    ShippingAddress_Street  nvarchar(100) NULL,
    ShippingAddress_City    nvarchar(60)  NULL,
    ShippingAddress_Postcode nvarchar(10) NULL
);

Reverse engineered literally, that is a Customer class with six string properties and no Address type anywhere. EF Core's answer is an owned entity: a type with no identity of its own, whose properties live in the owner's table. This setting is how you declare one.

You add a mapping per prefix. The generator then hides the prefixed columns from the POCO, generates an Address class, adds one property of that type, and emits the matching builder.OwnsOne(...) configuration.

Settings.AddOwnedEntityMappings = delegate(List<OwnedEntityMapping> mappings)
{
    mappings.Add(new OwnedEntityMapping
    {
        Schema       = Settings.DefaultSchema, // or "*" to match any schema
        Table        = "Customer",             // or "*" to match any table
        ColumnPrefix = "BillingAddress_",      // the columns to group
        PropertyName = "BillingAddress",       // the property on Customer
        PropertyType = "Address"               // the class to generate
    });

    mappings.Add(new OwnedEntityMapping
    {
        Schema       = Settings.DefaultSchema,
        Table        = "Customer",
        ColumnPrefix = "ShippingAddress_",
        PropertyName = "ShippingAddress",
        PropertyType = "Address"               // the same class, used twice
    });
};

Those five fields are all OwnedEntityMapping has. Full before-and-after output, including the generated Address class and the OwnsOne block, is on Owned Entities.

When to use it

  • Value objects flattened into columns. Addresses, money amounts, date ranges, audit stamps - any group of columns that is conceptually one thing.
  • The same shape on several tables. Use Table = "*" and the generator produces one Address class shared by all of them.
  • Cleaning up a wide table. Twenty columns become five properties, three of them owned entities.

Leave it alone if the columns only look related. An owned entity is a modelling claim, and EF will treat the group as a single value from then on.

Gotchas

One class per distinct PropertyType, deduplicated across mappings. Two mappings naming Address generate one Address class. If the two column groups are not the same shape, the first mapping wins and the second one's extra columns are lost. Give them different type names unless the shapes match exactly.

Nullability is decided by the winning mapping too. With BillingAddress_Postcode NOT NULL and ShippingAddress_Postcode NULL, the shared Address.Postcode takes whichever was added first. Read the generated class rather than assuming.

The prefix is matched case-insensitively and stripped, trailing separator included, so BillingAddress_Street becomes Address.Street and not Address.BillingAddress_Street.

EF Core only. On EF 6 the mappings are collected and then ignored. EF 6's nearest equivalent is a complex type, which this generator does not produce.

Write your own class outside the generated folder if you would rather hand-write Address. The generator writes one file per unique PropertyType and will overwrite yours if it lands in the same place.

This is not the JSON column feature. ExcludePropertyConfiguration belongs to JsonColumnMapping, not here. The two produce similar-looking nested types and are configured separately - see JSON column support.

See also

Clone this wiki locally