实体框架代码首先将 FK 双倍为 PK



我需要使用 Fntity Framework 代码映射一些实体——首先使用 Fluent API。

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

我将从Driver访问RacingVehicle,只能通过Contract(反之亦然(。像这样:

var teamName = ayrtonSenna.Contract.RacingVehicle.Team.Name;
var driverName = mcLaren.Contract.Driver.Name;

我将有一个ContractManager服务类来管理这些合同。

我相信Contract类一定映射为 PK,来自DriverRacingVehicle的 FK,对吧?

那么,我该如何映射呢?

您通常会在上下文类的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,或者添加代码来检查你的合约是否重叠。您不能仅通过主键轻松强制实施。

您应该能够在配置DBContext时进行此设置(有关详细信息,请参阅文档(。

简而言之,鉴于您的班级...

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

但请注意,这是指对象DriverRacingVehicle,而不是像stringint这样的简单值,所以我不完全确定这将如何工作(自从我使用 EF 以来已经有一段时间了(。

如果事实证明这是一个问题,我可以想到两种选择来尝试: 直接引用每个对象的Id字段:

modelBuilder.Entity<Contract>()
.HasKey(c => new { c.Driver.Id, c.RacingVehicle.Id });

。或者将字段DriverIdRacingVehicleId添加到Contract类中,并直接使用它们:

modelBuilder.Entity<Contract>()
.HasKey(c => new { c.DriverId, c.RacingVehicleId });

另一种选择是为Contract添加新的单独Id,并将其用作主键。从长远来看,从架构的角度来看,这可能是一个更好的解决方案;它将把关注点(驾驶员和车辆(更多地分开,并且将支持例如您希望为一辆车配备两个驾驶员(备用驾驶员?(的未来情况。

这还可以让您保留一段时间内驾驶员与车辆关系的历史记录(只需为每个合同添加开始日期和结束日期(。您当前的解决方案也可以支持这一点,但是每个驾驶员一次只能驾驶一辆车;你永远不能在不换车的情况下给同一个司机一份新合同。

缺点是您必须实现显式逻辑来检查驾驶员与车辆的关系,但这不应该太难,并且对于其他好处来说可能是值得的。

最新更新