具有 Entity Framework 核心 2.0 的多个子实体中的相同 属性 名称

Same property name in several child entities with Entity Framework Core 2.0

我目前正在使用下面的简单模型。这非常简单:我们有资源,它们可以是 RoomEmptyOffice (...) 或 Service

RoomEmptyOffice 可以有容量,但不能 Service.

public abstract class Resource : Entity
{
    public string Name { get; set; }
}

public class Room : Resource
{
    public int Capacity { get; set; }
}

public class EmptyOffice : Resource
{
    public int Capacity { get; set; }
}

public class Service : Resource
{ }

为了从我的 SQL 视图中获取数据,我使用映射:

builder.Entity<Resource>(m =>
{
    m.ToTable("resource", "facility");
    m.HasKey(x => x.Id);
    m.Property(x => x.Id)
        .HasColumnName("ResourceId");
    m.Property(x => x.Type)
        .HasColumnName("ResourceTypeId");

    m.HasDiscriminator(x => x.Type)
        .HasValue<Room>(ResourceType.Room)
        .HasValue<EmptyOffice>(ResourceType.EmptyOffice)
        .HasValue<Service>(ResourceType.Service);
});

builder.Entity<Room>();
builder.Entity<EmptyOffice>();
builder.Entity<Service>();

当我 运行 我的代码时,EF Core 抛出以下异常:

System.Data.SqlClient.SqlException: 'Invalid column name 'Room_Capacity'.'

如果我将 Capacity 属性 重命名为 Room_Capacity,它可以工作,但很糟糕。

如何强制 EF Core 2.0 为我的每个子实体设定目标容量 属性?

谢谢 塞巴斯蒂安

您不能这样做,因为 EF Core 中唯一可用的继承模式是每个 class 层次结构 table。如果你使用接口而不是基础 classes,你可以,但是每个实体将被映射到不同的 table。使用 [NotMapped] 标记要排除的任何 属性,或者使用代码,使用忽略。

这对我有用:

builder.Entity<Room>().Property(a => a.Capacity).HasColumnName("Capacity");

builder.Entity<EmptyRoom>().Property(a => a.Capacity).HasColumnName("Capacity");

我在项目的下一个代码中做了使其更通用的方式。

        private static void FindAndConfigureBackgroundJobResultTypes(ModelBuilder modelBuilder)
        {
            var backgroundJobResultTypes = typeof(BackgroundJobResult).Assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(BackgroundJobResult))).ToList();

            var sameTypeAndNameProperties = backgroundJobResultTypes
                .SelectMany(x => x.GetProperties())
                .GroupBy(d => new {d.Name, d.PropertyType})
                .Select(grp => new
                {
                    PropertyType = grp.Key.PropertyType,
                    PropertyName = grp.Key.Name,
                    Count = grp.Count()
                })
                .Where(x => x.Count > 1).ToList();


            foreach (var backgroundJobResultType in backgroundJobResultTypes)
            {

                //Set base type , instead of exposing this type by DbSet
                modelBuilder.Entity(backgroundJobResultType).HasBaseType(typeof(BackgroundJobResult));

                //Map properties with the same name and type into one column, EF Core by default will create separate column for each type, and make it really strange way. 
                foreach (var propertyInfo in backgroundJobResultType.GetProperties())
                {
                    if (sameTypeAndNameProperties.Any(x => x.PropertyType == propertyInfo.PropertyType && x.PropertyName == propertyInfo.Name))
                    {
                        modelBuilder.Entity(backgroundJobResultType).Property(propertyInfo.PropertyType, propertyInfo.Name).HasColumnName(propertyInfo.Name);
                    }
                }
            }
        }