具有每层次表的一对多实体框架为每个子类创建一个外键列

epa*_*alm 10 c# entity-framework one-to-many table-per-hierarchy

我有一个Garage包含CarsMotorcycles.汽车和摩托车是Vehicles.他们来了:

public class Garage
{
    public int Id { get; set; }
    public virtual List<Car> Cars { get; set; }
    public virtual List<Motorcycle> Motorcycles { get; set; }

    public Garage()
    {
        Cars = new List<Car>();
        Motorcycles = new List<Motorcycle>();
    }
}

public abstract class Vehicle
{
    public int Id { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
}

public class Car : Vehicle
{
    public int GarageId { get; set; }
    public virtual Garage Garage { get; set; }
    // some more properties here...
}

public class Motorcycle : Vehicle
{
    public int GarageId { get; set; }
    public virtual Garage Garage { get; set; }
    // some more properties here...
}
Run Code Online (Sandbox Code Playgroud)

为什么Car和Motorcycle都有GarageId和Garage属性?如果我将这些属性推送到Vehicle超类,EF抱怨并告诉我导航属性必须驻留在具体类中.

继续,这是我的DbContext:

public class DataContext : DbContext
{
    public DbSet<Garage> Garages { get; set; }
    public DbSet<Vehicle> Vehicles { get; set; }
    public DbSet<Car> Cars { get; set; }
    public DbSet<Motorcycle> Motorcycles { get; set; }

    public DataContext()
        : base("GarageExample")
    {

    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个与我的玩具一起玩的简短程序:

class Program
{
    static void Main(string[] args)
    {
        Database.SetInitializer<DataContext>(new DropCreateDatabaseAlways<DataContext>());

        using (var db = new DataContext())
        {
            var car1 = new Car { Make = "Subaru", Model = "Legacy" };
            var car2 = new Car { Make = "Porche", Model = "911" };

            var bike1 = new Motorcycle { Make = "Suzuki", Model = "GS500" };
            var bike2 = new Motorcycle { Make = "Kawasaki", Model = "Ninja" };

            var garage = new Garage();

            garage.Cars.Add(car1);
            garage.Cars.Add(car2);
            garage.Motorcycles.Add(bike1);
            garage.Motorcycles.Add(bike2);

            db.Garages.Add(garage);

            db.SaveChanges();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该程序运行,并生成以下车辆表:

Id Make     Model  GarageId GarageId1 Discriminator
1  Subaru   Legacy 1        null      Car
2  Porche   911    1        null      Car
3  Suzuki   GS500  null     1         Motorcycle
4  Kawasaki Ninja  null     1         Motorcycle
Run Code Online (Sandbox Code Playgroud)

由于Car和Motorcycle都有自己的GarageId和Garage属性,似乎每个子类都在创建自己的车库外键.我怎么告诉EF(通过流畅的api,如果可能的话)Car.Garage和Motorcycle.Garage是同一个东西,应该使用相同的列?

这当然是我想要的车辆表:

Id Make     Model  GarageId Discriminator
1  Subaru   Legacy 1        Car
2  Porche   911    1        Car
3  Suzuki   GS500  1        Motorcycle
4  Kawasaki Ninja  1        Motorcycle
Run Code Online (Sandbox Code Playgroud)

Ron*_*ald 5

在汽车和摩托车类的 GarageId 属性上使用属性 [Column("GarageId")]。


小智 -1

你看过这个了吗?

\n\n
\n

映射每个层次结构表 (TPH) 继承

\n\n

在 TPH 映射方案中,继承层次结构中的所有类型都映射到单个表。鉴别器列用于识别每行的类型。使用 Code First 创建模型时,TPH 是参与继承层次结构的类型的默认策略。默认情况下,鉴别器列将以名称 \xe2\x80\x9cDiscriminator\xe2\x80\x9d 添加到表中,并且层次结构中每种类型的 CLR 类型名称\n 用于鉴别器值。您可以使用 Fluent API 修改\n 默认行为。

\n
\n\n
modelBuilder.Entity<Course>() \n.Map<Course>(m => m.Requires("Type").HasValue("Course")) \n.Map<OnsiteCourse>(m => m.Requires("Type").HasValue("OnsiteCourse"));\n
Run Code Online (Sandbox Code Playgroud)\n\n

直接来自这里开始。

\n

  • 我对 EF 使用鉴别器列区分汽车和摩托车的方式没有任何疑问。 (4认同)