DbUpdateException与不暴露外键属性的实体 [英] DbUpdateException with entities that do not expose foreign key properties
问题描述
我有一个具有 User
和 Person
实体的实体模型,这样每个用户
必须与1 Person
相关联,每个 Person
可以关联零或1 用户
。
I have an entity model with User
and Person
entities, such that each User
must be associated with exactly 1 Person
, and each Person
can be associated zero or 1 User
.
User (0..1) <-------> (1) Person
关联流畅地映射。原来我只是在 Person
方面声明:
The association is mapped fluently. Originally I only had it declared on the Person
side:
private class PersonOrm : EntityTypeConfiguration<Person>
{
internal PersonOrm()
{
ToTable(typeof(Person).Name, DbSchemaName.People);
// has zero or one User
HasOptional(p => p.User)
.WithRequired(d => d.Person)
.Map(d => d.MapKey("PersonId"))
.WillCascadeOnDelete(false)
;
由于我遇到此错误,我还添加了相同的映射到用户
侧:
Since I encountered this error, I also added the same mapping to the User
side:
private class UserOrm : EntityTypeConfiguration<User>
{
internal UserOrm()
{
ToTable(typeof(User).Name, DbSchemaName.Identity);
// has exactly 1 Person
HasRequired(p => p.Person)
.WithOptional(d => d.User)
.Map(d => d.MapKey("PersonId"))
.WillCascadeOnDelete(false);
应用程序中有一个新的用户
可以创建并与现有的 Person
相关联。这是我目前困难的地方。 EF正在考虑 User
作为关系的依赖关系,并且正在放置一个 PersonId(FK,int,not null)
列中的用户
表。我不相信可以在任一实体上使用外键属性来帮助EF管理协会(是吗?)。
There is a scenario in the application where a new User
can be created and associated with an existing Person
. This is where I am having difficulty at the moment. EF is considering User
as the dependent side of the relationship, and is putting a PersonId (FK, int, not null)
column on the User
table. I don't believe it's possible to use a foreign key property on either entity to help EF manage the association (is it?).
这是一些尝试失败的代码以处理这种情况:
Here is some failing code that tries to handle the scenario:
// find out if Person already exists
var person = context.People.SingleOrDefault(p => p.Emails.Any(
e => e.Value.Equals(emailAddress, StringComparison.OrdinalIgnoreCase)));
// find out if User already exists
var user = context.Users.SingleOrDefault(
u => u.Name.Equals(emailAddress, StringComparison.OrdinalIgnoreCase));
if (user == null)
{
user = new User
{
Name = emailAddress,
IsRegistered = isRegistered,
Person = person ?? PersonFactory.Create(emailAddress),
// ignore the PersonFactory.Create, that part works
};
context.Entry(user).State = EntityState.Added;
context.SaveChanges();
}
当个人
为空(在db中不存在)。但是当 person
不为空(db中已经存在),而 user
为null时,代码会尝试创建一个新的用户
并将其与现有的 Person
相关联。当调用 SaveChanges()
时,我得到一个 DbUpdateException
:
This code works fine when person
is null (does not already exist in the db). However when person
is not null (already exists in db) and user
is null, the code attempts to create a new User
and associate it with the existing Person
. When invoking SaveChanges()
, I get a DbUpdateException
:
保存不会为其关系暴露外键
属性的实体时发生错误。 EntityEntries属性将
返回null,因为单个实体不能被识别为异常的源
。通过在您的实体类型中显示外键属性,可以更容易地处理例外情况。有关详细信息,请参阅
的InnerException。
An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.
内部异常是:
来自'User_Person'AssociationSet的关系在
'Deleted'状态。给定多重约束,相应的
'User_Person_Source'也必须处于已删除状态。
A relationship from the 'User_Person' AssociationSet is in the 'Deleted' state. Given multiplicity constraints, a corresponding 'User_Person_Source' must also in the 'Deleted' state.
这不会任何意义上,因为我不想删除任何东西,并检查用户
和<$的$ code> EntityState c $ c> Person 显示用户
在添加
状态,而code> Person 在 Unchanged
状态。我已经覆盖了 SaveChanges()
来演示:
This doesn't make any sense to me because I'm not trying to delete anything, and checking the EntityState
of both User
and Person
shows that User
is in the Added
state, whereas Person
is in the Unchanged
state. I have overridden SaveChanges()
to demonstrate:
public override int SaveChanges()
{
var userChanges = ChangeTracker.Entries<User>().Single();
var personChanges = ChangeTracker.Entries<Person>().Single();
if (userChanges.State == EntityState.Deleted)
throw new InvalidOperationException("wtf?");
if (personChanges.State == EntityState.Deleted)
throw new InvalidOperationException("wtf?");
return base.SaveChanges();
}
当此代码执行时, InvalidOperationException
被抛出。再次, userChanges
在添加
状态,而 personChanges
在不变
状态。
When this code executes, neither InvalidOperationException
is thrown. Again, userChanges
is in the Added
state, and personChanges
is in the Unchanged
state.
我做错了什么?
推荐答案
我现在觉得很笨。在写了这个仔细的问题之后,现在很明显。
I feel really dumb right now. After writing up this careful question, it's now obvious.
Person
我正在测试已经存在,已经有一个用户
与不同的 User.Name
的关联。这就是为什么 user
正在加载null。将 Person.User
属性设置为新的用户
导致旧的用户
被放入已删除
状态。卫生署。
The Person
I am testing with already exists, and already has a User
association with a different User.Name
. This is why user
is coming up null. Setting the Person.User
property to a new User
is causing the old User
to be put in the Deleted
state. Doh.
对不起浪费了你的时间。我会离开这个问题,除非同意删除它更好。
Sorry to have wasted your time. I'll leave the question up unless it's agreed it would be better to delete it.
这篇关于DbUpdateException与不暴露外键属性的实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!