エンティティモデルUser
とPerson
エンティティがあり、それぞれ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にすでに存在している)、user
nullの場合、コードは新しいものを作成し、User
それを既存のに関連付けようとしますPerson
。を呼び出すSaveChanges()
と、次のようになりますDbUpdateException
。
関係の外部キープロパティを公開していないエンティティの保存中にエラーが発生しました。単一のエンティティを例外のソースとして識別できないため、EntityEntriesプロパティはnullを返します。保存中の例外の処理は、エンティティタイプの外部キープロパティを公開することで簡単にできます。詳細については、InnerExceptionを参照してください。
内部の例外は次のとおりです。
'User_Person'AssociationSetからの関係は'Deleted'状態にあります。多重度の制約がある場合、対応する「User_Person_Source」も「削除済み」状態である必要があります。
私は何も削除しようとはしていないので、これは私には意味がありません。EntityState
両方をチェックして、が状態にあるのに対し、は状態にあることUser
をPerson
示します。私はデモンストレーションするためにオーバーライドしました: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
ます。
私は何が間違っているのですか?