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

c# - 不共享EF中主键的多态关联-LMLPHP

这是主表Vehicle,其中VehicleType是鉴别符(可能的值为'Car''Bike')。因此,如果VehicleType = 'Car',则SubId指向要记录在Car表中,如果VehicleType = 'Bike',则将指向记录到Bike表中。

而且plus表不共享主键值。

我想避免代码中的复杂逻辑,但是我不明白是否可以在此处使用继承(因此Car : VehicleBike : Vehicle)或至少使用导航属性(因此Car.VehicleBike.Vehicle可以工作)。所以问题是我可以使用其中的一些吗?如何实现呢?

最佳答案

表不共享主键值


因此,无法将其映射到一个应该为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; }
}


我通过TPH将表Vehicle分为实体CarVehicleBikeVehicle

modelBuilder.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));


另一方面,CarInfoBikeInfo必须具有自己的表,因此在这里我使用了TPC

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


最后,连接类:

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映射两个导航属性,则EF不会接受。

该模型的主要缺点是,您始终必须将“ Info”实体作为VehicleInfo对象。 EF将创建正确的子类型,但其编译时类型为VehicleInfo。同样,如果设置VehicleInfo属性,则必须记住提供正确的类型。您可以通过传递属性来缓解这种情况...

public class CarVehicle : Vehicle
{
    [NotMapped]
    public CarInfo CarInfo
    {
        get { return VehicleInfo as CarInfo; }
        set { VehicleInfo = value; }
    }
}


...与BikeVehicle中的相同。但是您将不能直接在LINQ查询中使用此属性,因为它没有(也不能被映射)。

此外,从简单的东西中执行的SQL ...

db.Set<CarVehicle>().Include(c => c.VehicleInfo).ToList();


...之所以如此庞大是因为EF在所有继承树中进行了挖掘。

关于c# - 不共享EF中主键的多态关联,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37235858/

10-10 07:14