8

我有一个带有UserPerson实体的实体模型,这样每个实体都User必须与 1 准确关联Person,并且每个实体都Person可以与零或 1 关联User

User (0..1) <-------> (1) Person

该关联被流畅地映射。最初我只是在Person旁边声明:

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

由于我遇到了这个错误,所以我也在User旁边添加了相同的映射:

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

在应用程序中有一个场景,User可以创建一个新的并将其与现有的Person. 这是我目前遇到困难的地方。EF 将其视为User关系的依赖方,并将PersonId (FK, int, not null)列放在User表上。我不相信可以在任一实体上使用外键属性来帮助 EF 管理关联(是吗?)。

这是一些尝试处理该场景的失败代码:

// 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();
}

此代码在person为 null 时工作正常(数据库中尚不存在)。但是,当personis not null (已经存在于 db 中)并且user为 null 时,代码会尝试创建一个新的User并将其与现有的Person. 调用时SaveChanges(),我得到DbUpdateException

保存不为其关系公开外键属性的实体时发生错误。EntityEntries 属性将返回 null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参阅 InnerException。

内部异常是:

来自“User_Person”AssociationSet 的关系处于“已删除”状态。给定多重约束,相应的“User_Person_Source”也必须处于“已删除”状态。

这对我来说没有任何意义,因为我没有尝试删除任何内容,而是检查EntityState两者UserPerson显示User处于Added状态,而Person处于Unchanged状态。我已经重写SaveChanges()以证明:

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处于Added状态,personChanges处于Unchanged状态。

我究竟做错了什么?

4

2 回答 2

7

我现在真的觉得很傻。在写下这个仔细的问题之后,现在很明显了。

Person我正在测试的已经存在,并且已经与User不同的User.Name. 这就是为什么user会出现空值。将Person.User属性设置为新属性User会导致旧属性User进入Deleted状态。多哈。

很抱歉浪费了您的时间。我会留下这个问题,除非它同意删除它会更好。

于 2012-04-11T20:29:41.780 回答
0

确保您在映射中定义了关系(实体类型配置)

例如:

this.HasRequired(t => t.QuoteResponse).WithMany(t => t.QuoteResponseItems).HasForeignKey(d => d.QuoteResponseID);

于 2013-11-29T15:51:28.347 回答