代码之家  ›  专栏  ›  技术社区  ›  Seb

在实体框架核心2.0的多个子实体中具有相同的属性名称

  •  2
  • Seb  · 技术社区  · 8 年前

    Room EmptyOffice (...) 或 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抛出以下异常:

    系统数据SqlClient。SqlException:“列名“Room\u Capacity”无效。”

    Capacity 属性到 Room_Capacity ,它有效,但很可怕。

    如何强制EF Core 2.0针对我的每个子实体的容量属性?

    非常感谢。

    3 回复  |  直到 8 年前
        1
  •  5
  •   Yrrol    7 年前

    builder.Entity<Room>().Property(a => a.Capacity).HasColumnName("Capacity");
    
    builder.Entity<EmptyRoom>().Property(a => a.Capacity).HasColumnName("Capacity");
    
        2
  •  1
  •   Ricardo Peres    8 年前

    您不能这样做,因为EF核心中唯一可用的继承模式是每个类的表层次结构。如果使用接口而不是基类,则可以,但每个实体将映射到不同的表。用[NotMapped]或(使用代码)用Ignore标记要排除的任何属性。

        3
  •  1
  •   grinay    6 年前

            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);
                        }
                    }
                }
            }