在EF中不共享主键的多态关联

时间:2016-05-15 08:00:38

标签: c# .net entity-framework

我必须使用以下架构支持第三方数据库(看起来像RoR样式?)。

DB diagram

这是主表车辆,其中 VehicleType 是一个鉴别器(可能的值为'Car''Bike')。因此,如果 VehicleType = 'Car',则 SubId 指向 Car 表中的记录,如果 VehicleType = 'Bike'然后将积分记录到自行车表。

并且加表不共享主键值。

我想避免在我的代码中使用复杂的逻辑,但是我无法理解我是否可以在这里使用继承(所以Car : VehicleBike : Vehicle)或者至少是导航属性(所以{{1} }和Car.Vehicle可以工作)。所以问题是我可以使用这个吗?如何实现这个?

1 个答案:

答案 0 :(得分:1)

  

表格不共享主键值

因此,无法将此映射到一个继承架构,该架构本应为TPT。不同的主键值会阻止这种情况。

剩下的是映射彼此连接的不同类,因此您至少可以使用导航属性而不是手动加入不相关的实体。我找到了一种方法来做到这一点,但它并不理想。实际上,它是非常做作的。但是看看它是否适合您。

我使用了这些课程:

public abstract class Vehicle
{
    public int VehicleId { get; set; }
    public string Name { get; set; }
    public VehicleInfo VehicleInfo { get; set; }
}
public class CarVehicle : Vehicle
{ }
public class BikeVehicle : Vehicle
{ }

public abstract class VehicleInfo
{
    public int ID { get; set; }
}
public class CarInfo : VehicleInfo
{
    public string Model { get; set; }
}
public class BikeInfo : VehicleInfo
{
    public bool IsEbike { get; set; }
}

我将表格Vehicle分成CarVehicle实体BikeVehiclemodelBuilder.Entity<Vehicle>().ToTable("Vehicle"); modelBuilder.Entity<Vehicle>() .Map<CarVehicle>(m => m.Requires("VehicleType").HasValue("Car")) .Map<BikeVehicle>(m => m.Requires("VehicleType").HasValue("Bike") .HasColumnType("CHAR") .HasMaxLength(4)); TPH

CarInfo
另一方面,

BikeInfomodelBuilder.Entity<VehicleInfo>() .Map<CarInfo>(c => { c.MapInheritedProperties().ToTable("Car"); c.Property(x => x.ID).HasColumnName("CarId"); c.Property(x => x.Model); }) .Map<BikeInfo>(c => { c.MapInheritedProperties().ToTable("Bike"); c.Property(x => x.ID).HasColumnName("BikeId"); c.Property(x => x.IsEbike); }); 必须有自己的表格,所以我在这里使用了TPC

modelBuilder.Entity<Vehicle>().HasRequired(c => c.VehicleInfo)
    .WithOptional().Map(m => m.MapKey("SubId"));

最后,连接课程:

VehicleInfo

通过使用基本类型Vehicle.VehicleInfo,可以通过一个外键SubId映射一个属性public class CarVehicle : Vehicle { public CarInfo CarInfo { get; set; } } public class BikeVehicle : Vehicle { public BikeInfo BikeInfo { get; set; } } 。这是不可能的:

SubId
如果您尝试通过VehicleInfo映射两个导航属性,则

EF不会接受它。

这种模式的主要缺点是你总是必须得到信息&#34;信息&#34;实体为VehicleInfo个对象。 EF将创建正确的子类型,但它们的编译时类型为VehicleInfo。同样,如果设置public class CarVehicle : Vehicle { [NotMapped] public CarInfo CarInfo { get { return VehicleInfo as CarInfo; } set { VehicleInfo = value; } } } 属性,则必须记住提供正确的类型。您可以通过传递属性来缓解这种情况......

BikeVehicle

...和db.Set<CarVehicle>().Include(c => c.VehicleInfo).ToList(); 中的相同。但是您无法直接在LINQ查询中使用此属性,因为它不是(并且无法)映射。

此外,执行的SQL来自简单的...

[HttpGet]
由于EF挖掘了所有继承树,所以......是非常棒的。