是否有可能捕获实体框架0..1到0..1关系? [英] Is it possible to capture a 0..1 to 0..1 relationship in Entity Framework?

查看:166
本文介绍了是否有可能捕获实体框架0..1到0..1关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有一种方法,使一个可空反向导航属性在实体框架可空的外键关系?在数据库的说法, 0..1到0..1 的关系。

我试过下面,但我不断收到错误消息:


  

无法确定类型类型1和2型之间的关联的主要终点。该协会的主要终点必须用的关系,流利的API或数据注解来明确配置。


 公共类类型1 {    公众诠释ID {搞定;组; }    公众诠释? Type2ID {搞定;组; }
    公共类型2类型2 {搞定;组; }
}公共类{2型    公众诠释ID {搞定;组; }    公众诠释? Type1ID {搞定;组; }
    公共类型1类型1 {搞定;组; }
}

据我所知,整数列在一个表或其他的只存在,但肯定应该是可以覆盖所有必要的情况下?例如:

  2型类型1
======== ===============
ID号| Type1ID
-------- ---------------
1 |空值
2 2 | 2

我已经使用的数据注释尝试(如 [ForeignKey的] 一端, [InverseProperty] 两个),但没有这些似乎帮助的事情。

如果可能的话,数据注解的解决办法是pferred超过流利的API $ P $。此外, INT?属性不是从任一类域角度看绝对必要,是否有帮助。

有一个有趣的解决方法这里这意味着它是不可能捕捉到这种在实体关系框架(实际上,这是可选的集合的一部分的项目) - 如果是这样,有没有支持这项任何文件

?。
解决方案

这不可能是硬就是我虽然当我看到你的问题。但同样我发现有一个一对一关联是奸诈的混蛋。在这里,我们走了。

我认为通过 0..1 - 0..1 你的意思是两个对象可以存在相互独立的,但也可能仅仅关联到彼此

让使其具体化。 驱动程序。试想一下,很多赛车和车手,其中包括卡拉和DriverA池。现在,假设你想卡拉得到关联到DriverA,你的实现是DriverA链接自己CARA。但是,一旦DriverA做到这一点,你要CARA成为DriverA只,卡拉协会是不可选的任何更多,所以它应该被设置为好,马上。

如何实现?

选项1:

如果是这种工作模式:

 公共类车
{
    公众诠释CarId {搞定;组; }
    公共字符串名称{;组; }
    公众诠释? DriverId {搞定;组; }
    公共虚拟驱动器驱动器{搞定;组; }
}公共类驱动程序
{
    公众诠释DriverId {搞定;组; }
    公共字符串名称{;组; }
    公众诠释? CarId {搞定;组; }
    公共虚拟小汽车{搞定;组; }
}

从技术上说, DriverA 可以有一个外键为卡拉卡拉的外键的 DriverB

因此​​,当外键 DriverA-卡拉建立你应该simulaneously建立反向外键 CARA-DriverA 。这是你应该在code做的,这意味着它是一个的业务规则的。而在现实中,它不是一个原子操作,所以你必须确保它在一个数据库事务的完成。

类模型至少支持使用情况,但它太宽容。它需要被限制。更重要的是,它不会与EF 工作。关于有设置一个主要结束EF投诉。如果你这样做,EF不会创建一个双向关联。

另外一种影射提出这里。我试过,但有两个可选协会:

驱动程序的映射配置

  this.HasOptional(T => t.Car).WithMany()HasForeignKey(D => d.CarId)。

的映射配置:

  this.HasOptional(T => t.Driver)。.WithMany()HasForeignKey(C => c.DriverId);

(没有数据注解替代)

我发现创建一个新的驾驶者与座驾时,在数据库中的EF只设置一个外键的值。你必须单独设置,并节省协会,管理自己的事务。与现有的对象,你还是要同时设置外键,虽然这可以被保存在一个的SaveChanges 电话。

更好的选择?让我们来看看...

选项2:

这是在你指的是链接提到的一对多关联。这种模式需要外部约束,但创建该协会是原子。而你仍然有在另一端一端的参考和收藏。并与EF轻松映射。

选项3

您可以创建一个结表 CarDriver 有两个外键,以驱动程序,这两者构成其独特的主键:

这是一个普通的许多-to-many关联。默认情况下,EF将映射为类模型,其中驱动程序有指向对方集合属性,和结合表并不直接映射

 公共类车
{
    公众诠释CarId {搞定;组; }
    公共字符串名称{;组; }
    公共虚拟的ICollection<驱动程序和GT;司机{搞定;组; }
}公共类驱动程序
{
    公众诠释DriverId {搞定;组; }
    公共字符串名称{;组; }
    公共虚拟的ICollection<汽车>汽车{搞定;组; }
}

现在协会的创建是一个原子操作。这是完全可能的映射这个模型EF。相互引用都消失了,但你仍然可以得到 FirstOrDefault()集合属性作为替代参考。

但有一个重要的疑难杂症。现在,每个对象都可以有的若干相关的同行。如果您创建一个协会,你需要,如果所涉及的对象没有任何关联但它检查一个codeD业务规则。也许这个选项比选择2更糟糕,但我提到它,因为下一个选项:

选项4

选项3是原子的,但它也需要外部约束。为了让关联排他性的,在 CarDriver 两列应有的唯一键,所以每一辆车或司机只能在表中出现一次。全部由自己1关联关系:通过这些指标的模型实现双向可选1。任何code做这个工作必须遵守的规则。安然无恙......

但是,你要吗?

您永远不会配置EF code-第一个选项4。不能用流利的映射,也没有数据注解。你不得不使用迁移做到这一点,或工作数据库第一。

如果该数据库由多个应用程序你最好的选择可能是牵制在数据模型的约束。如果该规则不可能改变,这也可能是一个可行的选择。但是,如果只有一个(或两个)应用程序,数据库和业务规则上工作的可以的在未来的变化我倒是preFER伴随codeD规则更宽松的数据模型。 codeD的商业逻辑是一个容易得多比数据模型改变。

此外,即使选择4,你需要的业务逻辑检查协会的存在,您尝试创建它之前,否则一个丑陋的数据库异常会为你做到这一点。

结论

选项1是最接近你想要什么。但我不喜欢同时设置外键的义务,它很容易被遗忘或未来开发商忽略。

不过,方案2和3中可以被忘记codeD业务规则方面更重的要求。而集合是不自然作​​为替代1结束。选项​​3有一定的吸引我,因为驱动程序在数据库完全独立的,该协会是一个创纪录非空的外键(数据库管理员往往喜欢太)。

选项4具有相同的吸引力,它是当多个应用程序必须实现需要的选项2和3被强加此外,即使codeD规则,忘记了外部约束的最佳选择,数据库约束是最终的渔获物。但它不容易被EF code-首次实施。

Is there a way to make a nullable reverse navigation property for a nullable Foreign Key relationship in Entity Framework? In database parlance, a 0..1 to 0..1 relationship.

I've tried as below, but I keep getting the error message:

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

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

I understand that the integer column can only exist in one table or the other, but surely it should be possible to cover all necessary cases? E.g:

Type1      Type2
========   ===============
ID         ID   | Type1ID
--------   ---------------
1          1    | null
2          2    | 2

I've tried using data annotations (e.g. [ForeignKey] on one end, [InverseProperty] on both), but none of those seem to help the matter.

If possible, a data annotation solution would be preferred over Fluent API. Also, the int? property isn't strictly necessary from a domain perspective for either class, if that helps.

There is an interesting work-around here which implies it isn't possible to capture this kind of relationship in Entity Framework (effectively, an item that is optionally part of a collection) - if so, is there any documentation that would support this?.

解决方案

"This can't be hard" is what I though when I read your question. But again I found that one-to-one associations are treacherous bastards. Here we go.

I assume that by 0..1 – 0..1 you mean that two objects can exist independent of each other, but may also be exclusively associated to one another.

Lets make it concrete. Car and Driver. Imagine a pool of many cars and drivers, among them CarA and a DriverA. Now suppose you want CarA to get associated to DriverA, and your implementation is that DriverA links himself to CarA. But as soon as DriverA does this, you want CarA to be for DriverA only, CarA's association is not optional any more, so it should be set as well, immediately.

How to implement that?

Option 1:

If this is the working model:

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

technically, DriverA can have a foreign key to CarA and CarA a foreign key to DriverB.

Therefore, when the foreign key DriverA-CarA is established you should "simulaneously" establish the reverse foreign key CarA-DriverA. That is something you should do in code, meaning that it's a business rule. And in reality, it's not an atomic operation, so you must make sure that it's done in one database transaction.

The class model at least supports the use case, but it's too permissive. It needs to be constrained. More importantly, it won't work with EF. EF complaints about having to set a principal end. And if you do that, EF will not create a bidirectional association.

An alternative mapping was proposed here. I tried that but with two optional associations:

In the Driver's mapping configuration:

this.HasOptional(t => t.Car).WithMany().HasForeignKey(d => d.CarId);

In the Car's mapping configuration:

this.HasOptional(t => t.Driver).WithMany().HasForeignKey(c => c.DriverId);

(There is no data annotation alternative)

I found that EF only sets one foreign key value in the database when creating a new driver and car. You have to set and save both associations separately, managing your own transaction. With existing objects you still have to set both foreign keys, although this can be saved in one SaveChanges call.

Better options? Let's see...

Option 2:

This is the one-to-many association as mentioned in the link you refer to. This model needs external constraints, but creating the association is atomic. And you've still got a reference on one end and a collection on the other end. And it maps easily with EF.

Option 3:

You could create a junction table CarDriver that has two foreign keys, to Car and Driver, both of which comprise its unique primary key:

This is a regular many-to-many association. By default, EF would map this as a class model in which Car and Driver have collection properties pointing to each other, and the junction table is not mapped directly:

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

Now the creation of association is an atomic operation. It's perfectly possible to map this model with EF. The mutual references are gone, but you still can get the FirstOrDefault() of the collection properties as a surrogate reference.

But there's an important gotcha. Now each object can have any number of associated counterparts. If you create an association, you need a coded business rule which checks if the the involved objects don't have any associations yet. Maybe this option is even worse than option 2. But I mentioned it because of the next option:

Option 4

Option 3 is atomic, but it also needs external constraints. To make an association exclusive, both columns in CarDriver should have unique keys, so each car or driver can only occur once in the table. By these indexes the model implements a bidirectionally optional 1:1 association all by itself. Any code working on it has to obey the rules. Safe and sound...

But do you want that?

You're never going to configure option 4 in EF code-first. Not with fluent mapping nor data annotations. You'd have to use Migrations to do it, or work database-first.

If the database is used by multiple applications your best option may be to pin down the constraints in the the data model. If the rule is not likely to change this may also be a viable option. However, if only one (or two) applications work on the database and the business rule may change in the future I'd prefer a more liberal data model accompanied by coded rules. Coded business logic is a lot easier to change than a data model.

Moreover, even with option 4 you need business logic to check the existence of the association before you try to create it, otherwise an ugly database exception will do this for you.

Conclusions

Option 1 is closest to what you want. But I don't like the obligation to set both foreign keys, it's easily forgotten or ignored by future developers.

But Option 2 and 3 have even heavier requirements in terms of coded business rules that can be forgotten. And the collections are unnatural as surrogate "1" ends. Option 3 has some appeal to me because Car and Driver are completely independent in the database and the association is a record with non-nullable foreign keys (DBAs tend to like that too).

Option 4 has the same appeal, and it is the best option when multiple applications would have to implement the external constraints that need to be imposed on option 2 and 3. Also, even if coded rules are forgotten, the database constraints are a final catch. But it can't easily be implemented by EF code-first.

这篇关于是否有可能捕获实体框架0..1到0..1关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆