在EF.6中使用数据注释的OneOrZero关系?

时间:2017-11-11 08:59:38

标签: asp.net entity-framework-6 relationship

我有2个表,它们之间的关系使用字段 TableId1 TableId2 进行链接。

我想要的是,如果两个数据都已关联,则字段将由主键值填充。

Table1 中的平均字段 TableId2 将由 Table2.Id 以及 TableId1 填充>表2 将填充 Table1.Id

并且,我还希望两个字段都可以为空。这意味着他们的nolink(数据是独立的)。

public class Table1
{
    [Key]
    public int Id { get; set; }
    public string table1_desc { get; set; }

    public int? TableId2 { get; set; }
    [ForeignKey("TableId2")]
    public Table2 Table2 { get; set; }
}

public class Table2
{
    [Key]
    public int Id { get; set; }
    public string Table2_desc { get; set; }

    public int? TableId1 { get; set; }
    [ForeignKey("TableId1")]
    public Table1 Table1 { get; set; }
}

我的问题是,如何使用数据注释解决此问题?那可能吗 ?。上面的代码给了我错误:

 Unable to determine the principal end of an association between the types 'ConsoleApplication1.Data2' and 'ConsoleApplication1.Data1'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

谢谢你, Jigu Haslim

2 个答案:

答案 0 :(得分:0)

不,这根本不可能 -

外键约束需要主体类型和依赖类型,因此您可以配置级联,如果是nessacary。这正是错误消息告诉你的内容。

如果你需要一个实际的例子,想想一只母猫和一只小猫。母猫是校长。它可以在没有小猫的情况下存在。但是小猫很大程度上依赖于它的主要母亲。

删除母亲,删除将级联到它的小猫。 删除孩子,母亲将继续生活。

所以你必须让一个实体成为主体

public class Table1
{
    [Key]
    public int Id { get; set; }
    public string table1_desc { get; set; }
    public Table2 Table2 { get; set; }
}

另一个是依赖

public class Table2
{
    [Key, ForeignKey("Table1")]
    public int Id { get; set; }
    public string Table2_desc { get; set; }

    public Table1 Table1 { get; set; }
}

答案 1 :(得分:0)

有一种方法可以做到这一点,但不是数据注释,我认为我不推荐它(如果你不喜欢它,请随时投票给我)。

诀窍是将两种关系映射为一对多。例如汽车和司机:

public class Car
{
    public int CarId { get; set; }
    public string Name { get; set; }
    public int? DriverId { get; set; }
    public Driver Driver { get; set; }
}

public class Driver
{
    public int DriverId { get; set; }
    public string Name { get; set; }
    public int? CarId { get; set; }
    public Car Car { get; set; }
}

映射:

modelBuilder.Entity<Driver>()
            .HasOptional(d => d.Car).WithMany()
            .HasForeignKey(d => d.CarId);
modelBuilder.Entity<Car>()
            .HasOptional(c => c.Driver).WithMany()
            .HasForeignKey(c =>c.DriverId);

但这是缺点。您必须从双方建立关系,否则您可以获得Car DriverId,而所属驱动程序有CarId = null。但如果你这样做......

var car = new Car { Name = "Ford" };
var driver = new Driver { Name = "Henry" };
driver.Car = car;
car.Driver = driver;

db.Set<Car>().Add(car);
db.SaveChanges();

......抛出异常:

  

无法确定相关操作的有效排序。由于外键约束,模型要求或存储生成的值,可能存在依赖关系。

是的,司机需要新车的主钥匙和新车的车钥匙。

所以这要求你这样做:

var car = new Car { Name = "Ford" };
var driver = new Driver { Name = "Henry" };
driver.Car = car;

db.Set<Car>().Add(car);

using(var ts = new TransactionScope())
{
    db.SaveChanges();
    car.Driver = driver;
    db.SaveChanges();
    ts.Complete();
}

不太优雅,是吗?

仅供参考:这是this answer中的一个选项的详细说明,您可以在其中找到更好的选择。