Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ef core: mapping value object using OwnsMany requires primary key to be defined

I have a class

public class Document
{
    public string TranId { get; set; }        
    public Record Record { get; set; }
    public List<Error> Errors { get; set; }
}

public class Record
{
    public string TranId { get; set; }    
    public List<DataResult> DataResults { get; set; }
}

public class DataResult
{
    public string DataSourceName { get; set; }
    public List<DataField> DataFields { get; set; }
    public List<CustomField> CustomFields { get; set; }        
}

I want to map Record and DataResult classes as Value objects so I tried to map as

public void Configure(EntityTypeBuilder<Document> builder)
{
    builder.ToTable("Document");
    builder.HasKey(x => x.TranId);

    builder.OwnsOne(a => a.Record, a =>
    {
        a.ToTable("Doc_Record");
        a.Property(p => p.TranId).HasMaxLength(100)
            .HasColumnName("TranID")
            .HasDefaultValue("");                          
            a.OwnsMany(x => x.DataResults, x =>
                {
                    x.ToTable("Doc_Rec_DataResults");
                    x.Property(p => p.DataSourceName).HasMaxLength(150)
                        .HasColumnName("DataSourceName")
                        .HasDefaultValue("");                                   
                });
    }
}

When I try to add this migration it errors with a message:

The entity type 'DataResult' requires a primary key to be defined.

  • And why it requires primary key cause I'm trying to map as a value object?

Someone suggested using this link and I try to add

a.OwnsMany(x => x.DataResults, x =>
{
    x.WithOwner().HasForeignKey("RecordId");
    x.ToTable("Doc_Rec_DataResults");
    x.Property(p => p.DataSourceName).HasMaxLength(150)
    .HasColumnName("DataSourceName")
    .HasDefaultValue("");                                   
});

but this approach is not working cause WithOwner is available from .net core 3 where I'm using .net core 2 (and do I really need to add RecordId property into Record class (it's a value object).

It would be great if someone can provide an example of how to map collection of value objects with OwnsMany in EF Core 2.

like image 608
user1765862 Avatar asked Oct 16 '22 10:10

user1765862


1 Answers

In this ef core 2.2 example, we have a Company that owns a collection of Addresses, here's the implementation. note that i omitted some useful code to stick to the point, refer to the full example for further explanation. Also note that this feature OwnsMany() is not available in pre ef core 2.2

public class CompanyAddress
{   
    public string City { get; }

    public string AddressLine1 { get; }
}


public class Company
{
    private List<CompanyAddress> addresses = new List<CompanyAddress>();

    public Guid Id { get; }

    public string Name { get; }

    public IEnumerable<CompanyAddress> Addresses { get => this.addresses; }

    public void AssignAddress(CompanyAddress address)
    {
        var exists = this.addresses.Contains(address);

        if (!exists)
        {
            this.addresses.Add(address);
        }
    }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Company>().OwnsMany<CompanyAddress>("Addresses", a =>
    {
        a.HasForeignKey("CompanyId");
        a.Property(ca => ca.City);
        a.Property(ca => ca.AddressLine1);
        a.HasKey("CompanyId", "City", "AddressLine1");
    });
}

here's a repo of full solution for the article's owner

like image 90
MHDuke Avatar answered Oct 27 '22 10:10

MHDuke