Han*_*ele 15 c# entity-framework foreign-keys
有没有办法在Entity Framework中为可为空的外键关系制作可空的反向导航属性?在数据库用语中,有一个0..1到0..1的关系.
我尝试过如下,但我不断收到错误消息:
无法确定类型"Type1"和"Type2"之间关联的主要结尾.必须使用关系流畅API或数据注释显式配置此关联的主要结尾.
public class Type1 {
public int ID { get; set; }
public int? Type2ID { get; set; }
public Type2 Type2 { get; set; }
}
public class Type2 {
public int ID { get; set; }
public int? Type1ID { get; set; }
public Type1 Type1 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我知道整数列只能存在于一个表或另一个表中,但是当然应该可以涵盖所有必要的情况吗?例如:
Type1 Type2
======== ===============
ID ID | Type1ID
-------- ---------------
1 1 | null
2 2 | 2
Run Code Online (Sandbox Code Playgroud)
我尝试过使用数据注释(例如,[ForeignKey]在一端,[InverseProperty]两者都有),但这些似乎都没有帮助.
如果可能,数据注释解决方案将优于Fluent API.此外,int? 对于任何一个类,从域的角度来看,属性并不是必需的,如果这有帮助的话.
这里有一个有趣的解决方法,这意味着不可能在实体框架中捕获这种关系(实际上,一个项目可选择是集合的一部分) - 如果是这样,是否有任何文档支持这一点? .
Ger*_*old 32
当我读到你的问题时,"这可不难".但我再次发现,一对一协会是奸诈的混蛋.开始了.
我假设0..1 – 0..1您的意思是两个对象可以彼此独立存在,但也可以彼此唯一关联.
让它具体化.Car和Driver.想象一下,有许多汽车和司机,其中包括CarA和DriverA.现在假设您希望CarA与DriverA相关联,并且您的实现是DriverA将自己链接到CarA.但是一旦DriverA做到这一点,你希望CarA仅用于DriverA,CarA的关联不再是可选的,所以它应该立即设置.
如何实现?
如果这是工作模式:
public class Car
{
public int CarId { get; set; }
public string Name { get; set; }
public int? DriverId { get; set; }
public virtual Driver Driver { get; set; }
}
public class Driver
{
public int DriverId { get; set; }
public string Name { get; set; }
public int? CarId { get; set; }
public virtual Car Car { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
从技术上讲,DriverA可以将CarA和CarA的外键作为DriverB的外键.

因此,当DriverA-CarA建立外键时,您应该"同时"建立反向外键CarA-DriverA.这是你应该在代码中做的事情,这意味着它是一个商业规则.实际上,它不是原子操作,因此您必须确保它在一个数据库事务中完成.
类模型至少支持用例,但它太宽容了.它需要受到限制.更重要的是,它不适用于EF.EF关于必须设定主要目标的投诉.如果你这样做,EF将不会创建双向关联.
在Driver映射配置中:
this.HasOptional(t => t.Car).WithMany().HasForeignKey(d => d.CarId);
Run Code Online (Sandbox Code Playgroud)
在Car映射配置中:
this.HasOptional(t => t.Driver).WithMany().HasForeignKey(c => c.DriverId);
Run Code Online (Sandbox Code Playgroud)
(没有数据注释替代)
我发现EF在创建新的驱动程序和汽车时只在数据库中设置了一个外键值.您必须分别设置和保存两个关联,管理您自己的事务.对于现有对象,您仍然必须设置两个外键,尽管可以在一次SaveChanges调用中保存.
更好的选择?让我们来看看...
这是您所指的链接中提到的一对多关联.此模型需要外部约束,但创建关联是原子的.你仍然在一端有一个参考,另一端有一个集合.它可以轻松映射到EF.
您可以创建一个CarDriver具有两个外键的联结表,Car并且Driver两者都包含其唯一的主键:

这是一个常规的多对多关联.默认情况下,EF将映射这是其中一类模式Car,并Driver有指向对方集合属性,并结合表不直接映射到:
public class Car
{
public int CarId { get; set; }
public string Name { get; set; }
public virtual ICollection<Driver> Drivers { get; set; }
}
public class Driver
{
public int DriverId { get; set; }
public string Name { get; set; }
public virtual ICollection<Car> Cars { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在,关联的创建是一个原子操作.使用EF映射此模型是完全可能的.相互引用已经消失,但您仍然可以FirstOrDefault()将集合属性作为代理引用.
但是有一个重要的问题.现在每个对象可以有任意数量的关联对应物.如果创建关联,则需要编码的业务规则,该规则检查所涉及的对象是否还没有任何关联.也许这个选项比选项2更差.但是我提到它是因为下一个选项:
选项3是原子的,但它也需要外部约束.要使关联独占,两列中的列CarDriver应具有唯一键,因此每个汽车或驱动程序只能在表中出现一次.通过这些索引,模型实现了双向可选的1:1关联.处理它的任何代码都必须遵守规则.安然无恙...
但你想要吗?
您永远不会首先在EF代码中配置选项4.没有流畅的映射或数据注释.您必须使用迁移来执行此操作,或者首先使用数据库.
如果数据库由多个应用程序使用,则最佳选择可能是确定数据模型中的约束.如果规则不太可能改变,这也可能是一个可行的选择.但是,如果只有一个(或两个)应用程序在数据库上工作,并且业务规则将来可能会发生变化,那么我更倾向于使用更自由的数据模型,并附带编码规则.编码业务逻辑比数据模型更容易更改.
此外,即使使用选项4,您还需要业务逻辑来在尝试创建关联之前检查关联的存在,否则丑陋的数据库异常将为您执行此操作.
选项1最接近您的要求.但是我不喜欢设置两个外键的义务,很容易被未来的开发人员遗忘或忽略.
但是,对于可以忘记的编码业务规则而言,选项2和3的要求更高.当代理"1"结束时,收藏品不自然.选项3有一定的吸引力我,因为Car和Driver在数据库完全独立的,协会是具有非空的外键的记录(数据库管理员往往也喜欢).
选项4具有相同的吸引力,当多个应用程序必须实现需要对选项2和3施加的外部约束时,它是最佳选择.此外,即使忘记了编码规则,数据库约束也是最终的限制.但它不能轻易地通过EF代码实现.
| 归档时间: |
|
| 查看次数: |
5919 次 |
| 最近记录: |