为何EF无法使用相同的外键来处理两个属性,但又将引用/实例分开? [英] Why can't EF handle two properties with same foreign key, but separate references/instances?

查看:229
本文介绍了为何EF无法使用相同的外键来处理两个属性,但又将引用/实例分开?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

显然,EF6不喜欢具有多个使用相同键值但不共享相同引用的外键属性的对象.例如:

Apparently, EF6 doesn't like objects that have multiple foreign key properties that use the same key value, but do not share the same reference. For example:

var user1 = new AppUser { Id = 1 };
var user2 = new AppUser { Id = 1 };

var address = new Address
{
    CreatedBy = user1, //different reference
    ModifiedBy = user2 //different reference
};

当我尝试插入此记录时,EF抛出此异常:

When I attempt to insert this record, EF throws this exception:

Saving or accepting changes failed because more than one entity of type
'AppUser' have the same primary key value. [blah blah blah]

我发现这样做可以解决问题:

I've discovered that doing this resolves the issue:

var user1 = new AppUser { Id = 1 };
var user2 = user1; //same reference

我可以编写一些辅助代码来对引用进行规范化,但是我宁愿EF仅仅知道它们是基于ID的同一对象.

I could write some helper code to normalize the references, but I'd rather EF just know they're the same object based on the ID alone.

关于EF为什么这样做,一种解释可能是它试图避免对同一对象执行多CRUD操作,因为同一实体的单独实例可能包含不同的数据.我希望能够告诉EF不要为此担心.

As for why EF does this, one explanation could be that its trying to avoid doing multipe CRUD operations on the same object since separate instances of the same entity could contain different data. I'd like to be able to tell EF not to worry about that.

更新

因此,正如我在上面的最后一段中所怀疑的那样.在没有一种方法可以告诉EF不要在任何一个实例上执行CRUD的情况下,我现在仅要这样做:

So it's as I suspected per my last paragraph above. In absense of a means to tell EF not to do CRUD on either instance, I will just do this for now:

if (address.ModifiedBy.Id == address.CreatedBy.Id)
{
    address.ModifiedBy = address.CreatedBy;
}

只要我不尝试对两者进行CRUD,就可以很好地工作.

Works well enough so long as I am not trying to do CRUD on either.

Update2

当我需要的只是子实体的ID时,我曾经采取过这种做法来防止EF验证否则需要的null属性.但是,它不会阻止EF对具有相同ID的单独实例进行烦恼.如果不打算对任一AppUser对象执行CRUD,为什么不关心实例是否不同?

I've previously resorted to doing this to prevent EF from validating otherwise-required null properties when all I need is the child entity's ID. However, it doesn't keep EF from going into a tizzy over separate instances with the same ID. If it's not going to do CRUD on either AppUser object, why does it care if the instances are different?

foreach (var o in new object[] { address.ModifiedBy, address.CreatedBy })
{
    db.Entry(o).State = EntityState.Unchanged;
}

推荐答案

解释是EF的变更跟踪器是 身份地图 . IE.数据库中的一条记录映射到一个CLR对象,并且只有一个.

The explanation is that EF's change tracker is an identity map. I.e. a record in the database is mapped to one, and only one, CLR object.

通过尝试使用相同的键附加两个对象可以很容易地证明这一点:

This can be demonstrated easily by trying to attach two objects with the same key:

context.AppUsers.Attach(new AppUser { Id = 1 });
context.AppUsers.Attach(new AppUser { Id = 1 });

第二行将引发异常:

附加类型为'AppUser'的实体失败,因为相同类型的另一个实体已经具有相同的主键值.

Attaching an entity of type 'AppUser' failed because another entity of the same type already has the same primary key value.

如果您进行分配,也会发生这种情况

This also happens if you assign

CreatedBy = user1, //different reference
ModifiedBy = user2 //different reference

在此过程中的某些地方,必须将user1user2附加到上下文,从而引起您所获得的异常.

Somewhere in the process, user1 and user2 must be attached to the context, giving rise to the exception you get.

显然,您有一个函数可以接收两个可以不同或相同的Id值.诚然,如果您可以简单地从这些Id创建两个AppUser实例,而不必担心相同的键,这将非常方便.不幸的是,您的解决方案...

Apparently, you have a function that receives two Id values that can be different or identical. Admittedly, it would be very convenient if you could simply create two AppUser instances from these Ids, not having to worry about identical keys. Unfortunately, your solution ...

if (address.ModifiedBy.Id == address.CreatedBy.Id)

...是必需的.固然足够.

... is necessary. Solid enough, though.

这篇关于为何EF无法使用相同的外键来处理两个属性,但又将引用/实例分开?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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