2012-01-06 64 views
18

我試圖創建具有特定角色的新用戶對象。 「角色」是EF中的一個現有實體。我用google搜索了一下,然後用stackoverflow,直到我臉色發青,我嘗試了所有似乎都適用於其他人的東西。但是當我嘗試保存新的用戶對象時,它首先嚐試創建一個新的「角色」,而不是僅僅通過引用現有角色來創建新的用戶對象。實體框架創建與現有實體關係的新實體,導致嘗試創建現有實體的新副本

我在做什麼錯?

Role myRole = new Role { ID = myUser.Role.ID }; 
myObjectContext.Roles.Attach(myRole); 
myUser.Role = myRole; 

if (myUser.ID == 0) 
{ 
    myObjectContext.Users.AddObject(myUser); 
} 
else 
{ 
    if (myUser.EntityState == System.Data.EntityState.Detached) 
    { 
     myObjectContext.Users.Attach(myUser); 
    } 
    myObjectContext.ObjectStateManager.ChangeObjectState(myUser, System.Data.EntityState.Modified); 
} 
myObjectContext.SaveChanges(SaveOptions.None); 

編輯 - 經過測試...

好吧..所以我無論如何發現的 「事業」 的一些部分。我仍然不知道爲什麼這樣做,需要幫助。

基本上,我有兩組數據附加到我的新用戶對象。一個是「角色」,它是角色表中包含角色的FK。這顯示爲用戶的導航屬性,如「User.Role」。

第二組數據是稱爲「FIPS」的對象的集合,這是用戶與稱爲FIPS的另一個表之間的多對多關係。它們之間有一個關係表,它只包含兩列,分別是用戶和FIPS的外鍵。用戶的FIPS也是一個像「User.FIPS」一樣被引用的導航屬性。

以下是顯示在保存上下文之前向用戶對象分配FIPS和角色的整個代碼。

List<string> fipsList = new List<string>(); 
foreach (FIPS fips in myUser.FIPS) 
{ 
    fipsList.Add(fips.FIPS_Code); 
} 
myUser.FIPS.Clear(); 
foreach (string fipsCode in fipsList) 
{ 
    FIPS myFIPS = new FIPS { FIPS_Code = fipsCode }; 
    myObjectContext.FIPSCodes.Attach(myFIPS); 
    myUser.FIPS.Add(myFIPS); 
} 


Role myRole = new Role { ID = myUser.Role.ID }; 
myObjectContext.Roles.Attach(myRole); 
myUser.Role = myRole; 


if (myUser.ID == 0) 
{ 
    myObjectContext.Users.AddObject(myUser); 
} 
else 
{ 
    if (myUser.EntityState == System.Data.EntityState.Detached) 
    { 
     myObjectContext.Users.Attach(myUser); 
    } 
    myObjectContext.ObjectStateManager.ChangeObjectState(myUser, System.Data.EntityState.Modified); 
} 

myObjectContext.SaveChanges(SaveOptions.None); 

設置我的手錶,以檢查「myObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added)」中看到的狀態。當事情被添加到這一點。

只要將第一個相關對象添加到用戶對象,第二個尚未附加到上下文的相關對象就會添加到EntityState爲「已添加」的上下文中。

....會看看是否有辦法避免將相關實體附加到用戶實體,直到它們全部被連接到上下文之後。

--FOLLOWUP-- 行..好,我改變了代碼的順序,使相關的實體都被分配給用戶的實體之前附加到上下文..但只要第一相關實體被分配,第二個相關實體在ObjectStateEntries中顯示爲「添加」。 因此,我將其更改爲以下順序:

  1. 將所有相關實體附加到上下文。
  2. 刪除用戶對象上的現有關係到相關實體 類型。
  3. 將相關實體分配給用戶實體。
  4. 保存用戶實體。

而..現在..它的工作.. omg它的作品...!=)

回答

4

我寫了下面的代碼已經有一段時間了,但我隱約記得遇到同樣的問題,它發生是因爲添加的角色目前正在被上下文跟蹤,所以附加存根具有使用相同的ID添加新角色。

在下面的代碼中,我首先檢查ChangeTracker,如果正在跟蹤角色,則使用現有條目。

// add roles that are in dto.Roles, but not in resource.Roles 
// use the change tracker entry, or add a stub role 
var rolesToAdd = fromDto.Roles.Where(r => !toResource.Roles.Any(role => role.Id == r)).ToList(); 
var roleEntries = dbContext.ChangeTracker.Entries<Role>(); 

foreach (var id in rolesToAdd) 
{ 
    var role = roleEntries.Where(e => e.Entity.Id == id).Select(e => e.Entity).FirstOrDefault(); 

    if (role == null) 
    { 
     role = new Role { Id = id }; 
     dbContext.Set<Role>().Attach(role); 
    } 

    toResource.Roles.Add(role); 
} 
+0

我正試圖解決這個問題。由於我在VS 2010 IDE中沒有「myObjectContext.ChangeTracker」選項,因此此代碼適用於不同版本的EF。 – 2012-01-06 15:57:05

+0

@AmandaMyer,它用於EF 4.2。如果你使用EF 4,你可以試試ObjectStateManager類。 – 2012-01-06 16:48:59

+0

這不是正確的答案,但它讓我開始解決問題,所以我接受了這個答案。 – 2012-01-06 19:03:17

-1

嘗試使用它來代替的前三行(這不應該是必要的,在所有的,如果用戶對象已經知道這是角色的ID和被丟棄反正):

int id = myUser.Role.ID; // Role should be NULL, if the user is actually new... 
         // could it be that you wanted to write myUser.RoleID? 
Role myRole = myObjectContext.Roles.FirstOrDefault(x => x.ID == id); 
myUser.Role = myRole; 
+0

試過這個。仍然有同樣的問題。謝謝。 =) – 2012-01-06 15:55:54

0

你爲什麼如果Role實體已經存在於數據庫中,則創建一個新實例?

無論如何,如果您想手動將新實例附加到上下文,它應該在數據庫中存在附加實例的ID時運行。但是,在你的情況下,下面行是有點奇怪:

Role myRole = new Role { ID = myUser.Role.ID }; 
myObjectContext.Roles.Attach(myRole); 
myUser.Role = myRole; 

首先創建一個具有來自現有Role實例(myUser.Role)的ID一個新的角色,那麼你附上你的新實例,然後最後你又影響你的實例給它來自的用戶。 這裏肯定有問題。 如果你的角色已經存在(當你在第一行寫上myUser.Role.ID,所以我假設它是這種情況),爲什麼你要創建一個新的實例。

放下那3條線。 從數據庫中獲取您的角色。然後影響來自數據庫的RolemyUser.Role屬性。

+0

原因是因爲我創建的用戶對象最初是作爲客戶端前端的json字符串創建的,然後通過webmethod將其反序列化,然後嘗試保存它。由於我不想調用數據庫來獲取角色信息的序列化,只是將其反序列化回數據庫,所以我簡單地設置了User.Role.ID屬性,並且認爲我會更新對該角色信息的引用保存方法內的角色。這就是我想要做的。 – 2012-01-06 15:35:34

+0

我曾嘗試直接從數據庫中分配它,而不是執行STUB和Attach方法,但它仍然執行相同的操作。 – 2012-01-06 15:56:28

+0

奇怪。你能發佈角色和用戶實體嗎? – ken2k 2012-01-06 16:00:51