我需要先使用Fluent API使用Fntity Framework代码映射某些实体。
我有一个Driver
和一个RacingVehicle
。我需要Driver
仅在一个RacingVehicle
中,并且一个RacingVehicle
只有一个Driver
。
展位类引用连接它们的Contract
(关联类?)。
Contract
显示了一些额外的信息:Driver
和他的RacingVehicle
之间的合同将持续多少年。
我当前的代码:
public class Driver
{
public Guid Id { get; protected set; }
public string Name { get; protected set; }
// others properties
public virtual Contract Contract { get; protected set; }
}
public class RacingVehicle
{
public Guid Id { get; protected set; }
public int Number { get; protected set; }
public virtual Team Team { get; protected set; }
// others properties
public virtual Contract Contract { get; protected set; }
}
public class Contract
{
public virtual Driver Driver { get; protected set; }
public virtual RacingVehicle RacingVehicle { get; protected set; }
public int SeasonsRemaining { get; protected set; }
}
我将仅通过RacingVehicle
从Driver
访问Contract
(反之亦然)。像这样:
var teamName = ayrtonSenna.Contract.RacingVehicle.Team.Name;
var driverName = mcLaren.Contract.Driver.Name;
我将有一个ContractManager
服务类来管理这些合同。
我相信Contract
类必须已映射为PK,即Driver
和RacingVehicle
的FK,对吧?
那么,我该如何映射呢?
答案 0 :(得分:1)
通常,您可以在上下文类的OnModelCreating()
方法中配置复杂的主键,如下所示:
public class Contract
{
public int DriverId { get; set; }
public virtual Driver Driver { get; set; }
public int RacingVehicleId { get; set; }
public virtual RacingVehicle RacingVehicle { get; set; }
public int SeasonsRemaining { get; set; }
}
public class RacingContext : DbContext
{
public DbSet<Driver> Drivers { get; set; }
public DbSet<RacingVehicle> RacingVehicles { get; set; }
public DbSet<Contract> Contracts { get; set; }
public override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Contract>().HasKey(contract => new { contract.DriverId, contract.RacingVehicleId });
}
}
但是,这意味着您不能添加重复的条目。因此,如果驾驶员“鲍勃”与迈凯伦签订了合同,那么当合同终止时,他又与迈凯伦又获得了另一份合同,则您必须删除旧合同或将其覆盖,以便存储新合同的详细信息。如果您不关心历史,仅对最新合同感兴趣,那么可以进行此设置。如果需要完整的历史记录,则必须为每个合同指定唯一的ID,或添加 code 以检查合同是否重叠。您不能仅通过主键轻松实施该操作。
答案 1 :(得分:0)
在配置DBContext
时,您应该可以进行设置(请参见the documentation for details)。
简而言之,给你上课...
public class Contract
{
public virtual Driver Driver { get; protected set; }
public virtual RacingVehicle RacingVehicle { get; protected set; }
public int SeasonsRemaining { get; protected set; }
}
..您应该能够根据以下模式指定组合键:
class YourContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Contract>()
.HasKey(c => new { c.Driver, c.RacingVehicle });
}
// ...
}
但是请注意,这是指对象Driver
和RacingVehicle
,而不是像string
或int
这样的简单值,因此我并不完全确定这将如何工作(自从我与EF合作以来已经有一段时间了)。
如果发现这是一个问题,我可以考虑尝试以下两种方法:直接引用每个对象的Id
字段:
modelBuilder.Entity<Contract>()
.HasKey(c => new { c.Driver.Id, c.RacingVehicle.Id });
......或将字段DriverId
和RacingVehicleId
添加到Contract
类中,并直接使用它们:
modelBuilder.Entity<Contract>()
.HasKey(c => new { c.DriverId, c.RacingVehicleId });
另一种选择是为Id
添加一个新的Contract
,并将其用作主键。从架构的角度来看,从长远来看,这可能是一个更好的解决方案。它将关注点(驾驶员和车辆)彼此分离,并会支持在未来的情况下,您需要一辆车有两个驾驶员(后备驾驶员?)。
这还可以让您保留一段时间内的驾驶员与车辆的关系历史记录(只需为每个合同添加起始日期和截止日期)。您当前的解决方案也可以提供支持,但是每个驾驶员只能驾驶一辆车辆一次。您必须在不更换汽车的情况下再给同一个驾驶员新的合同。
不利之处在于,您将必须实施显式逻辑来检查驾驶员与车辆之间的关系,但这不应太难,并且可能值得其他好处。