C# 具有两个独立表和一个从属表的多个一对一关系
我已经读了很多关于这个话题的相关问题,但是没有一个能解决我的问题,所以请耐心听我说。 我是EF的新手,尝试在ASP.NET MVC中使用EF6建立以下关系: 我需要两张固定的桌子,司机和汽车。现在,当一个驾驶员与一辆汽车关联时,我需要在这些表之间创建一个关系但只能为一辆车分配一名驾驶员。 驾驶员可能并不总是与汽车相关联,反之亦然,我希望维护这两个表,即使它们之间并不总是有关联,因此我认为我需要一个额外的表专门用于建立此连接。我认为这将在这些类之间建立1:1:1的关系 下面是我的POCO类的模型 型号C# 具有两个独立表和一个从属表的多个一对一关系,c#,entity-framework,ef-fluent-api,C#,Entity Framework,Ef Fluent Api,我已经读了很多关于这个话题的相关问题,但是没有一个能解决我的问题,所以请耐心听我说。 我是EF的新手,尝试在ASP.NET MVC中使用EF6建立以下关系: 我需要两张固定的桌子,司机和汽车。现在,当一个驾驶员与一辆汽车关联时,我需要在这些表之间创建一个关系但只能为一辆车分配一名驾驶员。 驾驶员可能并不总是与汽车相关联,反之亦然,我希望维护这两个表,即使它们之间并不总是有关联,因此我认为我需要一个额外的表专门用于建立此连接。我认为这将在这些类之间建立1:1:1的关系 下面是我的POCO类的模型
public class Driver
{
public int DriverID { get; set; }
public string Name { get; set; }
//other additional fields
public DriverCar DriverCar { get; set; }
}
public class Car
{
public int CarID { get; set; }
public string Brand { get; set; }
//other additional fields
public DriverCar DriverCar { get; set; }
}
public class DriverCar
{
public int DriverCarID { get; set; }
public int DriverID { get; set; }
public Driver Driver { get; set; }
public int CarID { get; set; }
public Car Car { get; set; }
}
我曾尝试使用Fluent API配置关系,但我认为我完全错了,因为我遇到了以下错误:
在上引入外键约束“FK_dbo.DriverCar_dbo.Car_CarId”
表'DriverCar'可能导致循环或多个级联路径。具体说明
删除不操作或更新不操作,或修改其他外部
关键制约因素。无法创建约束或索引。见前文
错误
流畅的Api
modelBuilder.Entity<DriverCar>()
.HasRequired(a => a.Driver)
.WithOptional(s => s.DriverCar)
.WillCascadeOnDelete(false);
modelBuilder.Entity<DriverCar>()
.HasRequired(a => a.Car)
.WithOptional(s => s.DriverCar)
.WillCascadeOnDelete(false);
modelBuilder.Entity()
.HasRequired(a=>a.Driver)
.with可选(s=>s.DriverCar)
.WillCascadeOnDelete(假);
modelBuilder.Entity()
.HasRequired(a=>a.Car)
.with可选(s=>s.DriverCar)
.WillCascadeOnDelete(假);
我真的不确定我是否遗漏了什么,或者是否有更好的方法来处理这种情况,如果有人能给我一些关于如何解决这个问题的反馈,我将不胜感激
更新 我在这里找到了一个有趣的答案: 我相信这正是我想要的:0..1对0..1的关系。但所有提到的选项似乎都太复杂了,我不太确定哪一个是最好的,甚至不知道如何正确地实现它们 在EF中,这些类型的关系应该很难实现吗?
例如,我尝试了选项1,但它从两个表中创建了0..1对多关系-驾驶员对汽车和汽车对驾驶员。那么,我该如何在它们之间创建一个独特的关联呢?请为您的模型尝试此方法。虚拟启用延迟加载,并建议使用导航属性。显示外键的数据注释(或使用fluent)以确保每个关系使用的是正确的键
public class Driver
{
public int DriverID { get; set; }
public string Name { get; set; }
//other additional fields
public DriverCar? DriverCar { get; set; }
}
public class Car
{
public int CarID { get; set; }
public string Brand { get; set; }
//other additional fields
public DriverCar? DriverCar { get; set; }
}
public class DriverCar
{
public int DriverCarID { get; set; }
[ForeignKey("Driver")]
public int DriverID { get; set; }
public Driver Driver { get; set; }
[ForeignKey("Car")]
public int CarID { get; set; }
public Car Car { get; set; }
}
modelBuilder.Entity<Driver>()
.HasOptional(a => a.DriverCar)
.WithRequired(s => s.Driver)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Car>()
.HasOptional(a => a.DriverCar)
.WithRequired(s => s.Car)
.WillCascadeOnDelete(false);
公共类驱动程序
{
public int DriverID{get;set;}
公共字符串名称{get;set;}
//其他附加字段
公共驱动器CAR?驱动器CAR{get;set;}
}
公车
{
public int CarID{get;set;}
公共字符串品牌{get;set;}
//其他附加字段
公共驱动器CAR?驱动器CAR{get;set;}
}
公共类驱动程序
{
public int DriverCarID{get;set;}
[外国钥匙(“司机”)]
public int DriverID{get;set;}
公共驱动程序{get;set;}
[外国钥匙(“汽车”)]
public int CarID{get;set;}
公共小汽车{get;set;}
}
modelBuilder.Entity()
.has可选(a=>a.DriverCar)
.WithRequired(s=>s.Driver)
.WillCascadeOnDelete(假);
modelBuilder.Entity()
.has可选(a=>a.DriverCar)
.需要(s=>s.Car)
.WillCascadeOnDelete(假);
注意:更改为外键的数据注释。倒装流利的语句。修正了驾驶员与汽车之间的第二种关系。这里有一个简单的方法来创建一对零的关系。请注意,我是一个将所有表的Id保持为Id的粉丝,而不是CarId等,这只是我的风格。这只是一个控制台应用程序,因此一旦添加EF nuget,您就可以进行复制/粘贴 但是下面的代码与.NETFramework4.6和EF6.2配合使用,它创建了以下表格 汽车
- Id(主键,整数,非空)
- 驱动程序Id(FK、int、null)
- Id(主键,整数,非空)
using System.Data.Entity;
namespace EFTest
{
class Program
{
static void Main(string[] args)
{
var connectionString = "<your connection string>";
var context = new DatabaseContext(connectionString);
var car = new Car();
var driver = new Driver();
context.Cars.Add(car);
context.Drivers.Add(driver);
car.Driver = driver;
context.SaveChanges();
}
}
public class Car
{
public int Id { get; set; }
public virtual Driver Driver { get; set; }
}
public class Driver
{
public int Id { get; set; }
}
public class DatabaseContext : DbContext, IDatabaseContext
{
public DbSet<Car> Cars { get; set; }
public DbSet<Driver> Drivers { get; set; }
public DatabaseContext(string connectionString) : base(connectionString){ }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasKey(n => n.Id)
.HasOptional(n => n.Driver);
modelBuilder.Entity<Driver>()
.HasKey(n => n.Id);
}
}
}
使用System.Data.Entity;
命名空间EFTest
{
班级计划
{
静态void Main(字符串[]参数)
{
var connectionString=“”;
var context=新数据库上下文(connectionString);
var car=新车();
var driver=新驱动程序();
context.Cars.Add(car);
context.Drivers.Add(驱动程序);
汽车司机=司机;
SaveChanges();
}
}
公车
{
公共int Id{get;set;}
公共虚拟驱动程序{get;set;}
}
公务舱司机
{
公共int Id{get;set;}
}
公共类DatabaseContext:DbContext、IDatabaseContext
{
公共数据库集车辆{get;set;}
公共数据库集驱动程序{get;set;}
公共数据库上下文(字符串connectionString):基(connectionString){}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasKey(n=>n.Id)
.has可选(n=>n.Driver);
modelBuilder.Entity()
.HasKey(n=>n.Id);
}
}
}
但是,如果您真的想强制每个汽车和驾驶员只有一个映射的约束,您可以使用下面的代码来实现。注意,w
using System.Data.Entity;
namespace EFTest
{
class Program
{
static void Main(string[] args)
{
var connectionString = "your connection string";
var context = new DatabaseContext(connectionString);
//Create a car, a driver, and assign them
var car = new Car();
var driver = new Driver();
context.Cars.Add(car);
context.Drivers.Add(driver);
context.SaveChanges();
var assignment = new DriverAssignment() { Car_id = car.Id, Driver_Id = driver.Id };
context.DriverAssignments.Add(assignment);
context.SaveChanges();
//Create a new car and a new assignment
var dupCar = new Car();
context.Cars.Add(dupCar);
context.SaveChanges();
var dupAssignment = new DriverAssignment() { Car_id = dupCar.Id, Driver_Id = driver.Id };
context.DriverAssignments.Add(dupAssignment);
//This will throw an exception because it will violate the unique index for driver. It would work the same for car.
context.SaveChanges();
}
}
public class Car
{
public int Id { get; set; }
}
public class Driver
{
public int Id { get; set; }
}
public class DriverAssignment
{
public int Car_id { get; set; }
public int Driver_Id { get; set; }
}
public class DatabaseContext : DbContext, IDatabaseContext
{
public DbSet<Car> Cars { get; set; }
public DbSet<Driver> Drivers { get; set; }
public DbSet<DriverAssignment> DriverAssignments { get; set; }
public DatabaseContext(string connectionString) : base(connectionString) { }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>().HasKey(n => n.Id);
modelBuilder.Entity<Driver>().HasKey(n => n.Id);
modelBuilder.Entity<DriverAssignment>().HasKey(n => new { n.Car_id, n.Driver_Id });
modelBuilder.Entity<DriverAssignment>().HasIndex(n => n.Car_id).IsUnique();
modelBuilder.Entity<DriverAssignment>().HasIndex(n => n.Driver_Id).IsUnique();
}
}