回答
使用外鍵更新實體優於導航屬性,因爲您不必處理實體的狀態。使用導航屬性更新實體時最常見的問題是在您可能預期相反的情況下獲取重複記錄。假設你有這個簡單的模型:
public class Post
{
public int Id {get; set;}
public string Title {get; set;}
[ForeignKey("CategoryId")]
public Category Category {get; set;}
public int CategoryId {get; set;}
}
public class Category
{
public int Id {get; set;}
public string Name {get; set;}
}
現在讓我們假設你有一個更新Post的控制器動作。認爲視圖有列出所有類別的列表框,用戶可以更改它。
PostController中立即更新
[HttpPost]
public ActionResult UpdatePost(PostDTO, post)
{
//Retrived the chosen category using its own "repository" class
Category newCategory = categoryRepository.Get(post.CategoryId);
//other validations here..
//Call method to update passing postDTO and the existing category
postRepository.Update(post, newCategory)
}
,在PostRepository,你做這樣的事情:
public void Update(PostDTO postDTO, Category category)
{
using (var context = new ScreencastContext())
{
//Get the post in this context
var post = context.Post.SingleOrDefault(x => x.Id == postDTO.Id);
post.Name = postDTO.Name;
//set other Post fields...
//Set the new category to the post
//this category already exists in the database and was retrieved by another "context"
post.Category = category;
context.Post.Attach(post);
context.Entry(post).State - EntityState.Modified;
context.SaveChanges();
}
}
也許你會認爲實體框架將 「趕上」 你的等級對象已經存在於數據庫中,並且只會更新Post表中的外鍵標識。 錯誤。 它實際上會創建一個新的類別,這是因爲當您從另一個上下文中檢索該類別時,此上下文不會將其識別爲圖形的一部分,而無法識別的實體具有默認狀態「已添加」。所以當你調用SaveChanges時,它會創建一個新的類別。
你可以自己管理實體的狀態來解決這個問題,但是這會變得非常複雜,並且很容易被許多怪異的代碼弄得無法理解。這就是外鍵派上用場的時候。
以上更新方法可以rewriten到這樣的事情:
public void Update(PostDTO postDTO, Category category)
{
using (var context = new ScreencastContext())
{
//Get the post in this context
var post = context.Post.SingleOrDefault(x => x.Id == postDTO.Id);
post.Name = postDTO.Name;
//set other Post fields...
//Set the new category to a post
//this category already exists in the database and was retrived by another "context"
post.CategoryId = category.Id;
//This just prevent any accidental navigation property being set.
post.Category = null;
context.Post.Attach(post);
context.Entry(post).State = EntityState.Modified;
context.SaveChanges();
}
}
這樣,你只更新後的表。一個新的類別將不會創建,並且一切都將按預期工作。
這件事,我發現在我自己的工作場所發生,很多時候,我總是指人這個驚人文章由朱莉·勒曼寫:
Why Does Entity Framework Reinsert Existing Objects into My Database?
這太神奇了,謝謝。 如果您僅使用類別ID,爲什麼要進行此調用: 類別newCategory = categoryRepository.Get(post.CategoryId); 僅通過Id並避免此調用並不是更高效? –
是的,如果你可以保證傳遞給控制器的Id是一個實際存在的Id,你可以跳過這個呼叫。我只是這樣做的,所以你可以理解查詢另一個類的數據並在其他類中使用它的「上下文」問題。還有一個併發問題:如果有人在更新Post時刪除了該類別,該怎麼辦?這就是爲什麼你再次檢查。 – jpgrassi
哇,這太好了,我有一個可以肯定會隨時刪除的物品。所以,貨幣可能是一個嚴重的問題。 非常感謝,我確認,你給的文章寫得非常好。 –
- 1. 實體框架:通過導航屬性
- 2. 實體框架導航屬性更新
- 3. 更新實體不更新導航屬性 - 實體框架
- 4. 使用實體框架更新外鍵
- 5. 使用實體框架的導航屬性更新數據庫
- 6. 使用實體框架(MVC3 Razor)更新導航屬性
- 7. 實體框架更新導航實體
- 8. 實體框架 - 通過屬性更新
- 9. 使用實體框架添加具有新導航屬性的新實體
- 10. 實體框架在新創建的實體上使用導航屬性
- 11. WPF和實體框架導航屬性
- 12. 實體框架數據庫更新:外鍵引用無效列(導航屬性)
- 13. 如何使用組合鍵更新實體的導航屬性?
- 14. 在實體implemening導航屬性框架
- 15. 更新外鍵採用實體框架
- 16. 實體框架:映射沒有導航屬性的外鍵?
- 17. 具有組合外鍵的實體框架導航屬性
- 18. 實體框架,外鍵和實體鍵
- 19. 實體框架 - 創建和使用導航屬性
- 20. 通過導航屬性實體框架,繼承和條件
- 21. 實體框架 - 通過集合導航和包含屬性
- 22. 通過SQL外鍵關係獲取實體框架的導航屬性
- 23. 正確使用實體框架中的導航屬性
- 24. 實體框架5不更新兩個實體中的導航屬性
- 25. 更新實體框架5中不與其導航屬性級聯的實體
- 26. 更新實體框架中的外鍵
- 27. 實體框架代碼優先 - 設置外鍵/導航屬性
- 28. 使用RIA服務和實體框架通過導航屬性從數據庫表中刪除實體
- 29. 實體框架導航屬性爲null
- 30. 實體框架 - 創建導航屬性
你能分享一些例子嗎? – jpgrassi