6

我有UserPerson實體,使得每個User必須正好1 Person相關聯,並且每個Person可以關聯零或1 User的實體模型。DbUpdateException與實體不公開外鍵的屬性

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作爲關係的相關方,並在User表上放置PersonId (FK, int, not null)列。我不相信可以在任何一個實體上使用外鍵屬性來幫助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爲空(沒有在數據庫已經存在)。但是,當person不爲空(已存在於db中)且user爲空時,代碼將嘗試創建新的User並將其與現有的Person關聯。當調用SaveChanges(),我得到一個DbUpdateException:保存不爲他們的關係暴露的外鍵 性實體

發生錯誤。 EntityEntries屬性 將返回null,因爲無法將單個實體標識爲異常的源 。通過在您的實體類型中公開外鍵屬性,可以更輕鬆地處理異常,同時保存 。有關詳細信息,請參閱 InnerException。

內部異常是:

從 'User_Person' AssociationSet的關係是在 '刪除' 狀態。考慮到多重性約束,相應的「User_Person_Source」也必須處於「已刪除」狀態。

這沒有任何意義,我,因爲我沒有試圖刪除任何東西,並檢查都UserPersonEntityState表明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狀態。

我在做什麼錯?

回答

6

我現在真的很啞。寫完這個小心的問題後,現在很明顯。

Person我正在測試已存在,並已有User關聯不同User.Name。這就是爲什麼user即將變爲空。將Person.User屬性設置爲新的User正在導致將舊的User置於Deleted狀態。衛生署。

對不起,你的時間浪費了。除非同意刪除它,否則我會留下問題。

+0

那麼你如何得到這個?我有一個類似的問題,有一個最後一個職位關聯的主題。如果將最後一篇文章設置爲不同的文章,它會嘗試刪除前一篇文章!跆拳道是關於? – leen3o 2012-07-13 08:57:37

+2

這是*關於*時間從EF切換到NHibernate的ORM! J/K ...就我而言,這是因爲多重性的限制。每個用戶**必須擁有一個人,但一個人可以有一個空用戶。當我將Person.User設置爲null時,EF首先檢查約束以查看關係的另一端(User.Person)是否可以設置爲null。由於它不能,EF會將用戶置於已刪除狀態。如果我將User.Person設置爲null,Person將不會**進入已刪除狀態,因爲它可以有0..1個用戶。如果您的約束條件不同,請提出問題,我會看一看。 – danludwig 2012-07-13 13:50:57

0

請確保您有(實體類型配置)在映射定義的關係

例如:

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