简体   繁体   English

具有两个独立表和一个从属表的多重一对一关系

[英]Multiple one-to-one relationship with two independent tables and one dependent

I have read a lot of related questions about this topic but none of them seemed to address my problem, so please bear with me.我已经阅读了很多关于这个主题的相关问题,但它们似乎都没有解决我的问题,所以请耐心等待。 I am new to EF and trying to establish the following relationship, in ASP .NET MVC, using EF6:我是 EF 的新手,并尝试在 ASP .NET MVC 中使用 EF6 建立以下关系:

I need to have two permanent tables, Drivers and Cars.我需要有两个永久表,Drivers 和 Cars。 I now need to create a relationship between these tables when a Driver is associated to a Car.当 Driver 与 Car 关联时,我现在需要在这些表之间创建关系。 But one Driver can only be assigned to one Car.但是一个 Driver 只能分配给一个 Car。

A Driver may not always be associated to a Car and vice-versa and I want to maintain both tables even if there isn't always an association between them, so that is why I believe I need to have an additional table exclusively to make this connection. Driver 可能并不总是与 Car 相关联,反之亦然,即使它们之间并不总是存在关联,我也想维护这两个表,所以这就是为什么我认为我需要一个额外的表来专门做这个联系。 Which I think will create a 1:1:1 relationship between these classes.我认为这将在这些类之间创建 1:1:1 的关系。

Below is the model for my POCO classes.以下是我的 POCO 课程的模型。

Models楷模

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; }
 }

I have tried configuration the relationships using Fluent API but I believe I am doing it completly wrong since I have got errors such as:我已经尝试使用 Fluent API 配置关系,但我相信我做错了,因为我遇到了以下错误:

Introducing FOREIGN KEY constraint 'FK_dbo.DriverCar_dbo.Car_CarId' on table 'DriverCar' may cause cycles or multiple cascade paths.在表 'DriverCar' 上引入 FOREIGN KEY 约束 'FK_dbo.DriverCar_dbo.Car_CarId' 可能会导致循环或多个级联路径。 Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。 Could not create constraint or index.无法创建约束或索引。 See previous errors.请参阅以前的错误。

Fluent Api流利的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);

I am really not sure if I am missing something or if there is some better approach to handle this situation and I would appreciate so much if someone can give me some feedback on how to solve this.我真的不确定我是否遗漏了什么,或者是否有更好的方法来处理这种情况,如果有人能给我一些关于如何解决这个问题的反馈,我将不胜感激。


Update更新

Just found an interesting answer here: Is it possible to capture a 0..1 to 0..1 relationship in Entity Framework?刚刚在这里找到了一个有趣的答案: Is it possible to capture a 0..1 to 0..1 relationship in Entity Framework? Which I believe is exactly what I want: a 0..1 to 0..1 relationship.我相信这正是我想要的:0..1 到 0..1 的关系。 But all the mentioned options seem too complex and I'm not quite sure which one is the best or how to even correctly implement them.但是所有提到的选项似乎都太复杂了,我不太确定哪一个是最好的,或者如何正确实施它们。

Are these type of relationships supposed to be so hard to implement in EF?这些类型的关系应该在 EF 中很难实现吗? For example, I tried Option 1 but it created a 0..1 to many relationship from both tables - Driver to Car and Car to Driver.例如,我尝试了选项 1,但它从两个表中创建了一个 0..1 到多的关系 - Driver to Car 和 Car to Driver。 How am I suppose to create an unique association between them then?那么我该如何在它们之间创建独特的关联呢?

Try this for your models.为您的模型试试这个。 Virtual enables lazy loading and is advised for navigation properties. Virtual 启用延迟加载并建议用于导航属性。 DataAnnotations showing the Foreign Keys (or use fluent) to be sure each relationship is using the correct key. 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);

Note: Changed to Data Annotations for Foreign Keys.注意:更改为外键的数据注释。 Inverted fluent statements.倒置流畅的语句。 Fixed Driver to Car in second relationship.在第二个关系中固定驱动程序到汽车。

Here is a simple way to create a one to zero.这是创建从一到零的简单方法。 Note that I'm a fan of keeping the Id of all tables as just Id, not CarId etc, just my style.请注意,我喜欢将所有表的 Id 保持为 Id,而不是 CarId 等,只是我的风格。 This is just a console app so once you add the EF nuget you could just copy/paste.这只是一个控制台应用程序,因此一旦您添加了 EF nuget,您就可以复制/粘贴。

But the below code works with .net framework 4.6 and EF6.2 It creates the following tables但是下面的代码适用于 .net framework 4.6 和 EF6.2 它创建了下表

Car

  • Id (PK, int, not null) Id (PK, int, not null)
  • Driver_Id (FK, int, null) Driver_Id (FK, int, null)

Driver司机

  • Id (PK, int, not null) Id (PK, int, not null)

Under this schema a Car can have only one driver.在这种模式下,一辆汽车只能有一个司机。 A driver may still drive multiple cars though.不过,一个司机仍然可以驾驶多辆汽车。 I'm not sure if that's an issue for you or not.我不确定这对你来说是否有问题。

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

        }
    }

But if you REALLY wanted to enforce the constraint of only one mapping per car and driver, you could do it with the code below.但是,如果您真的想对每个汽车和驾驶员强制执行仅一个映射的约束,则可以使用以下代码来实现。 Note that when you have the joining entity, you don't put it's Id anywhere on the joined entities.请注意,当您拥有加入实体时,您不会将其 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();
    }

}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM