我读了很多关于这个主题的相关问题,但似乎没有一个能解决我的问题,所以请耐心等待。我是EF的新手,并试图在ASP.NETMVC中使用EF6:建立以下关系
我需要两张固定的桌子,司机和汽车。当Driver与Car关联时,我现在需要在这些表之间创建一个关系但是一个驾驶员只能分配给一辆车
驾驶员可能并不总是与汽车相关,反之亦然,我希望维护这两个表,即使它们之间并不总是有关联,所以这就是为什么我认为我需要专门有一个额外的表来建立这种联系。我认为这将在这些类之间创建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配置关系,但我认为我做得完全错误,因为我遇到了以下错误:
在上引入FOREIGN KEY约束"FK_dbo.DriverCar_dbo.CarId"表"DriverCar"可能导致循环或多个级联路径。具体说明ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREINGKEY约束。无法创建约束或索引。参见上一页错误。
Fluent 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);
我真的不确定我是否遗漏了什么,或者是否有更好的方法来处理这种情况,如果有人能就如何解决这个问题给我一些反馈,我将不胜感激。
更新
刚刚在这里找到了一个有趣的答案:是否可以在实体框架中捕获0..1到0..1的关系?我相信这正是我想要的:一段0..1对0..1的关系。但所有提到的选项似乎都太复杂了,我不太确定哪一个是最好的,也不确定如何正确地实现它们。
这些类型的关系应该很难在EF中实现吗?例如,我尝试了选项1,但它从两个表创建了0..1对多的关系——Driver到Car和Car到Driver。那么,我该如何在它们之间建立一种独特的联系呢?
为您的模型尝试一下。Virtual支持延迟加载,建议使用导航属性。DataAnnotations显示外键(或使用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);
注:已更改为外键的数据注释。颠倒流畅的语句。修正了第二段关系中驾驶员与汽车的关系。
这里有一个创建一到零的简单方法。请注意,我喜欢将所有表的Id保持为justId,而不是CarId等,只是我的风格。这只是一个控制台应用程序,所以一旦你添加了EF nuget,你就可以复制/粘贴了。
但是下面的代码适用于.net框架4.6和EF6.2。它创建了以下表格
汽车
- Id(PK,int,非null(
- Driver_Id(FK,int,null(
驱动
- Id(PK,int,非null(
在此模式下,一辆汽车只能有一名驾驶员。不过,一名司机仍然可以驾驶多辆车。我不确定这对你来说是否是个问题。
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);
}
}
}
但是,如果你真的想强制每个汽车和司机只能有一个映射的约束,你可以用下面的代码来实现。请注意,当您拥有联接实体时,不会将其Id放在联接实体上的任何位置。
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();
}
}
}