11

我有一个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...
}

为什么 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>();
    }
}

这是一个玩我的玩具的小程序:

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

程序运行,并生成以下Vehicles表:

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

Car 和 Motorcycle 都有自己的 GarageId 和 Garage 属性,似乎每个子类都在创建自己的车库外键。我如何告诉 EF(通过流利的 api,如果可能的话) Car.Garage 和 Motorcycle.Garage 是同一件事,应该使用同一列?

这是我想要的Vehicles表,当然:

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
4

4 回答 4

5

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

于 2014-11-27T14:20:45.563 回答
3

我知道获取单个外键列和您想要的数据库架构的唯一方法是放弃每个派生类型的导航集合,Garage并使用单个集合作为基类型:

public class Garage
{
    public int Id { get; set; }
    public virtual List<Vehicle> Vehicles { get; set; }

    public Garage()
    {
        Vehicles = new List<Vehicle>();
    }
}

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

    public int GarageId { get; set; }
    public virtual Garage Garage { get; set; }
}

public class Car : Vehicle
{
    // some more properties here...
}

public class Motorcycle : Vehicle
{
    // some more properties here...
}

当然,当您只想加载aCar的 s 或MotorcyclesGarage并且您必须加载Vehiclea 的所有 sGarage或使用投影或显式加载来加载派生类型时,您将失去具有延迟或急切加载的舒适类型过滤器。

在我看来,您正在尝试做的事情是完全有效的,但不知何故,Entity Framework 不支持它,或者映射到 FK 列的方式没有以支持这种情况的方式实现。

于 2014-01-02T22:57:03.343 回答
0
    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 int GarageId { get; set; }
        public string Make { get; set; }
        public string Model { get; set; }
    }

    public class Car : Vehicle
    {
        [ForeignKey("GarageId")]
        public virtual Garage Garage { get; set; }
        // some more properties here...
    }

    public class Motorcycle : Vehicle
    {
        [ForeignKey("GarageId")]
        public virtual Garage Garage { get; set; }
        // some more properties here...
    }
于 2019-08-13T02:36:08.503 回答
-1

你看过这个了吗?

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

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

modelBuilder.Entity<Course>() 
.Map<Course>(m => m.Requires("Type").HasValue("Course")) 
.Map<OnsiteCourse>(m => m.Requires("Type").HasValue("OnsiteCourse"));

直接从这里开始。

于 2014-01-02T22:16:20.057 回答