DbUpdateException与不暴露外键属性的实体 [英] DbUpdateException with entities that do not expose foreign key properties

查看:461
本文介绍了DbUpdateException与不暴露外键属性的实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有 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屋!

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