Dominik Barkmann
Dominik Barkmann

Reputation: 43

EF Core Configuring Complex Types

I'm learning C# at the moment with .NET Core and EF Core for working with database.

Now I'm at the point where I got stuck configuring my entities.

I have written the following classes:

public class Customer
{
    #region Properties
    public Guid CustomerID { get; set; }
    ...
    public Address Address { get; set; }
    #endregion

    public Customer()
    {
        Address = new Address();
    }
}

public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
    public void Configure(EntityTypeBuilder<Customer> builder)
    {
        //Primary Key
        builder.HasKey(c => c.CustomerID);

        //Complex Types
        builder.OwnsOne<Address>("Address");
    }
}

public class Employee
{
    #region Properties
    public Guid EmployeeID { get; set; }
    ...
    public Address Address { get; set; }
    #endregion

    public Employee()
    {
        Address = new Address();
    }
}

public class EmployeeConfiguration : IEntityTypeConfiguration<Employee>
{
    public void Configure(EntityTypeBuilder<Employee> builder)
    {
        //Primary Key
        builder.HasKey(c => c.EmployeeID);

        //Complex Types
        builder.OwnsOne<Address>("Address");
    }
}

public class Address
{
    public string Street { get; set; }
    public string ZipCode { get; set; }
    public string City { get; set; }
    public State State { get; set; }
    public Country Country { get; set; }
}

I need to configure Address class with Fluent API that Address.Street is for Customer and Employee MaxLength = 50?

Is it possible to configure it for both at the same time? Or do I need to configure it for each entity?

Thanks for your help!

Upvotes: 4

Views: 2782

Answers (3)

lauxjpn
lauxjpn

Reputation: 5254

The valid answer of @Gert Arnold demonstrates, how to accomplish what you want for all of your target entities in a centralized way.

In case you want to keep the information in your configuration classes, then you can define it there instead (but it could be a bit more redundant, depending on the case):

public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
    public void Configure(EntityTypeBuilder<Customer> builder)
    {
        //Primary Key
        builder.HasKey(c => c.CustomerID);

        //Complex Types
        builder.OwnsOne(e => e.Address)
            .Property(e => e.Street)
            .HasMaxLength(50);
    }
}

public class EmployeeConfiguration : IEntityTypeConfiguration<Employee>
{
    public void Configure(EntityTypeBuilder<Employee> builder)
    {
        //Primary Key
        builder.HasKey(c => c.EmployeeID);

        //Complex Types
        builder.OwnsOne(e => e.Address)
            .Property(e => e.Street)
            .HasMaxLength(42); // or 50 if you want
    }
}

Upvotes: 2

Gert Arnold
Gert Arnold

Reputation: 109255

You can set all kinds of attributes of model types at once because they're easily accessible by modelBuilder.Model.GetEntityTypes(). Setting max length of owned type properties can be done like so:

var ownedAddresses = modelBuilder.Model.GetEntityTypes()
    .Where(t => t.IsOwned() && t.ClrType == typeof(Address))
    .ToList();
foreach (var address in ownedAddresses)
{
    address.FindProperty("Street").SetMaxLength(50);
}

...after the owned types have been registered to the model builder, i.e. after you added the type configurations.

Of course, the Where(t => t.IsOwned() predicate is redundant here. It's just to show another way to find owned types.

Upvotes: 1

Link
Link

Reputation: 1711

Until the current stable version of Entity Framework Core (3.1.6) this is not possible. Quote:

Instances of owned entity types cannot be shared by multiple owners (this is a well-known scenario for value objects that cannot be implemented using owned entity types)

Source: https://learn.microsoft.com/en-us/ef/core/modeling/owned-entities#current-shortcomings.

Your only option here would be to make Address an Entity itself with its own table. Then you would have an many-to-one relation from Customer / Employee (many) to Address (one).

For this you would have to extend your Address with a primary key and Customer and Employee with a foreign key each referencing Address. Then as you would do normally you can create a TypeConfiguration with your validation rules.

Upvotes: -1

Related Questions