gpt4 book ai didi

c# - 在 Entity Framework 中包含派生类型的嵌套对象的最佳方式是什么?

转载 作者:行者123 更新时间:2023-11-30 16:51:45 27 4
gpt4 key购买 nike

我需要在实体中包含嵌套对象。问题是还需要嵌套在嵌套对象中的嵌套对象,并且在它之上这些二级嵌套对象是不同类型的。我将展示一个与我的案例类似的例子,不要担心模式对你是否有意义,我只是想举一个更简单的例子。所以:

public class Garage
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Driver> Drivers { get; set; }
}

public abstract class Vehicle<TDriver, TMechanic>
where TDriver : Driver
where TMechanic : Mechanic
{
public virtual ICollection<TDriver> Drivers { get; set; }
public virtual ICollection<TMechanic> Mechanics { get; set; }
}

public class Car : Vehicle<CarDriver, CarMechanic>
{
// Some properties
}

public class Truck : Vehicle<TruckDriver, TruckMechanic>
{
// Some properties
}

public abstract class Driver
{
public int Id { get; set; }
public string Name { get; set; }
public int GarageId { get; set; }
public virtual Garage Garage { get; set; }
}

public class CarDriver : Driver
{
public int CarId { get; set; }
public virtual Car Car { get; set; }
}

public class TruckDriver : Driver
{
public int TruckId { get; set; }
public virtual Truck Truck { get; set; }
}

public abstract class Mechanic
{
public int Id { get; set; }
}

public class CarMechanic : Mechanic
{
public int CarId { get; set; }
public virtual Car Car { get; set; }
}

public class TruckMechanic : Mechanic
{
public int TruckId { get; set; }
public virtual Truck Truck { get; set; }
}

假设出于某种原因,Driver 可以拥有 Car 或 Truck,这就是此类结构的原因。

现在,当我创建一个新的 Garage 实体并在其中创建新的 Drivers 时,我只提供其 Car 或 Truck 实体的 ID。创建带有嵌套 Driver 实体的新 Garage 实体后,一切正常,除了 Driver 实体(CarDriver 或 TruckDriver)仅加载了它们的 CarId 和 TruckId 字段。问题是我还需要真正的 Car 和 Truck 实体。那么,我该如何包含它们呢?

下面这行不起作用。

context.Garages.Include(g => g.Drivers) 

我想到的唯一一件事(而且我知道这是我能做的最愚蠢的事情)是创建 DbContext 对象的新实例并通过 Id 获取 Garage 实体。

有谁知道如何在不采取这种愚蠢的解决方法的情况下应对这种情况?

编辑:我添加了 Vehicle、Mechanic、CarMechanic 和 TruckMechanic 类,以便我的示例可以更类似于我的真实代码。现在,从这个例子来看,将 Car 对象作为 CarDrivers 和 CarMechanics 的车辆没有多大意义。但就我而言,这是相关的。

最佳答案

Let's say that for some reason a Driver can have either a Car or a Truck and that's the reason for this class structure.

...

The thing is that I need also the real Car and Truck entities. So, how can I include them?

您似乎希望能够以多态方式访问每个驾驶员的车辆。但显然,你没有在基地上暴露这样的车辆Driver类,并且由于您正在使用 Garage.Drivers 访问您的数据(它正在使用该基础 Driver 类),您最终会遇到车辆无法进入的问题。

现在,在理想的世界中,您只需执行以下操作:

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

public class Car : Vehicle { public string CarSpecificProperty { get; set; } }
public class Truck : Vehicle { public string TruckSpecificProperty { get; set; } }

public abstract class Driver<TVehicle> where TVehicle : Vehicle
{
public virtual TVehicle Vehicle { get; set; }
}

public class CarDriver : Driver<Car> {}
public class TruckDriver : Driver<Truck> {}

问题是 Entity Framework 将拒绝映射开放的通用实体,您将无法创建适当的 DbSet<Driver<?>>在您的上下文中。

这将要求我们想出一种不太干净的方法:

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

public class Car : Vehicle { public string CarSpecificProperty { get; set; } }
public class Truck : Vehicle { public string TruckSpecificProperty { get; set; } }

public abstract class Driver
{
public int Id { get; set; }
public virtual Vehicle Vehicle { get; set; }
}

public class CarDriver : Driver
{
public Car Car
{
get { return this.Vehicle as Car; }
set { this.Vehicle = value as Car; }
}
}

public class TruckDriver : Driver
{
public Truck Truck
{
get { return this.Vehicle as Truck; }
set { this.Vehicle = value as Truck; }
}
}

在你的DbContext :

public IDbSet<Driver> Drivers { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CarDriver>().Ignore(x => x.Car);
modelBuilder.Entity<TruckDriver>().Ignore(x => x.Truck);

base.OnModelCreating(modelBuilder);
}

实际的用法是:

var driversWithVehicles = context.Drivers.Where(x => x.Vehicle != null);
var driversWithToyotaVehicles = context.Drivers.Where(x => x.Vehicle.Make == "Toyota");

var carDrivers = context.Drivers.OfType<CarDriver>();
var carDriversWithCriteria = context.Drivers.OfType<CarDriver>().Where(x => (x.Vehicle as Car).CarSpecificProperty == "SomeValue");

var truckDrivers = context.Drivers.OfType<TruckDriver>();
var truckDriversWithCriteria = context.Drivers.OfType<TruckDriver>().Where(x => (x.Vehicle as Truck).TruckSpecificProperty == "SomeValue");

(请注意,我们不使用 Car/Truck 属性访问 .Car/.Truck 特定数据,因为它们是有意忽略的,并且 EF 在尝试访问它们时会抛出异常)

现在,解决最后一个问题,这是您的原创 GarageInclude问题:

context.Garages.Include(g => g.Drivers.Select(d => d.Vehicle));

或者

context.Garages.Include("Drivers.Vehicle");

当然你现在也可以查询那些Drivers直接数据:

var allGaragesWithCars = context.Garages.Where(g => g.Drivers.OfType<CarDriver>().Any());

关于c# - 在 Entity Framework 中包含派生类型的嵌套对象的最佳方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33538894/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com