有没有办法用 EF Core 映射复杂类型

108*_*108 5 .net c# entity-framework-core .net-core

EF Core 不支持复杂类型映射。

如果我有一个对象,例如:

public class Entity { 
    public string StringProp {get; set;}
    public SubEntity NestedEntity {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

其中子实体是:

public class SubEntity{
    public int IntProp {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

我如何将其映射到包含 StringProp 和 IntProp 列的表。基本上表中的一条记录由实体和子实体的属性组成。

我试过忽略 SubEntity 并在 Entity 中公开它的属性,但这不起作用,因为当 NestedEntity 被忽略时,Entity 上使用其属性的任何属性都没有值。

除了创建具有复杂类型的所有属性的类或重构数据库之外,还有其他选择吗?

Bla*_*olf 10

更新:

在这个答案时,[ComplexType]属性似乎适用于 EF Core 2.0-3.1。我相信从 .NET 5 及以上版本,或者至少 .NET 6 以上版本开始,[Owned]应该改用该属性。原始答案已更新以反映这一点。

原来的:

自 EF Core 2.0 起,ComplexType 映射现已可用。目前我知道有两种方法可以做到这一点。

通过属性

不指定 Column 属性可能会导致实体框架无法将属性映射到现有表中的正确列而不进行迁移。

例如,它可能映射到 Address_StreetAddress

using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;

public class User
{
    public int Id { get; set; }

    // The complex property we want to use
    public Address Address { get; set; }

    public string UserName { get; set; }
}
    
// Lets Entity Framework know this class is a complex type
[Owned]
public class Address
{
    // Maps the property to the correct column name
    [Column("Address")]
    public string StreeAddress { get; set; }

    [Column("City")]
    public string City { get; set; }

    [Column("State")]
    public string State { get; set; }

    [Column("Zip")]
    public string ZipCode { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

通过流畅的API

不指定 HasColumnName 可能会导致实体框架无法将属性映射到现有表中的正确列而不进行迁移。

例如,它可能映射到 Address_StreetAddress

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

public class MyContext: DbContext
{
    public DbSet<User> Users { get; set; }

    public MyContext(DbContextOptions<MyContext> options)
        : base(options) { }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<User>(table =>
        {
            // Similar to the table variable above, this allows us to get
            // an address variable that we can use to map the complex
            // type's properties
            table.OwnsOne(
                x => x.Address,
                address =>
                {
                    address.Property(x => x.City).HasColumnName("City");
                    address.Property(x => x.State).HasColumnName("State");
                    address.Property(x => x.StreetAddress).HasColumnName("Address");
                    address.Property(x => x.SuiteNumber).HasColumnName("SuiteNumber");
                    address.Property(x => x.ZipCode).HasColumnName("Zip");
                });
        });
    }
}
Run Code Online (Sandbox Code Playgroud)