8

エンティティモデルUserPersonエンティティがあり、それぞれUserを正確に1Personに関連付ける必要があり、それぞれPersonを0または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の場合に正常に機能します(データベースにまだ存在していません)。ただし、personがnullではなく(dbにすでに存在している)、usernullの場合、コードは新しいものを作成し、Userそれを既存のに関連付けようとしますPerson。を呼び出すSaveChanges()と、次のようになりますDbUpdateException

関係の外部キープロパティを公開していないエンティティの保存中にエラーが発生しました。単一のエンティティを例外のソースとして識別できないため、EntityEntriesプロパティはnullを返します。保存中の例外の処理は、エンティティタイプの外部キープロパティを公開することで簡単にできます。詳細については、InnerExceptionを参照してください。

内部の例外は次のとおりです。

'User_Person'AssociationSetからの関係は'Deleted'状態にあります。多重度の制約がある場合、対応する「User_Person_Source」も「削除済み」状態である必要があります。

私は何も削除しようとはしていないので、これは私には意味がありません。EntityState両方をチェックして、が状態にあるのに対し、は状態にあることUserPerson示します。私はデモンストレーションするためにオーバーライドしました:UserAddedPersonUnchangedSaveChanges()

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.Nameuserこれがnullになる理由です。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 に答える