C#Entity-Framework:如何在模型对象上组合.Find和.Include?

Ral*_*h N 137 c# asp.net-mvc entity-framework

我正在做mvcmusicstore练习教程.我在为专辑管理器创建脚手架时注意到了一些事情(添加删除编辑).

我想优雅地编写代码,所以我正在寻找干净的方式来编写它.

仅供参考我正在使商店更通用:

专辑=项目

类型=类别

艺术家=品牌

以下是检索索引的方式(由MVC生成):

var items = db.Items.Include(i => i.Category).Include(i => i.Brand);
Run Code Online (Sandbox Code Playgroud)

以下是检索删除项的方法:

Item item = db.Items.Find(id);
Run Code Online (Sandbox Code Playgroud)

第一个带回所有项目并填充项目模型中的类别和品牌模型.第二个,没有填充类别和品牌.

我怎么能写第二个来做查找并填充里面的内容(最好是一行)...理论上 - 类似于:

Item item = db.Items.Find(id).Include(i => i.Category).Include(i => i.Brand);
Run Code Online (Sandbox Code Playgroud)

Den*_*aub 150

您需要先使用Include(),然后从生成的查询中检索单个对象:

Item item = db.Items
              .Include(i => i.Category)
              .Include(i => i.Brand)
              .SingleOrDefault(x => x.ItemId == id);
Run Code Online (Sandbox Code Playgroud)

  • 这可行,但使用"Find"和"SingleOrDefault"之间存在差异."Find"方法从本地跟踪的商店返回该对象(如果存在),避免往返数据库,其中使用"SingleOrDefault"将强制查询数据库. (72认同)
  • 我真的建议使用后者(SingleOrDefault),ToList将首先检索*all*条目然后选择一个 (23认同)
  • 如果我们有一个复合主键并使用相关的查找重载,则会中断. (5认同)
  • @Iravanchi是对的.这可能对用户有用,但据我所知,操作及其副作用并不等同于Find. (3认同)
  • 实际上没有回答操作问题,因为它没有使用.Find (3认同)
  • 此外,我建议使用“FirstOrDefault”而不是“SingleOrDefault”。第一个将生成“SELECT TOP(1)”,而第二个将生成“SELECT TOP(2)”以确保只有一个项目具有特定谓词。虽然不多,但没有正当理由选择比必要的更多的数据,除非您确实想确保您要查找的项目*必须*在表中是唯一的。 (3认同)
  • 尝试`... ToList().查找(id)`或`... SingleOrDefault()`代替.见修改后的答案. (2认同)

Lea*_*ner 68

丹尼斯的回答是使用IncludeSingleOrDefault.后者绕过数据库.

另一种方法是Find结合使用Load,明确加载相关实体......

MSDN示例下面:

using (var context = new BloggingContext()) 
{ 
  var post = context.Posts.Find(2); 

  // Load the blog related to a given post 
  context.Entry(post).Reference(p => p.Blog).Load(); 

  // Load the blog related to a given post using a string  
  context.Entry(post).Reference("Blog").Load(); 

  var blog = context.Blogs.Find(1); 

  // Load the posts related to a given blog 
  context.Entry(blog).Collection(p => p.Posts).Load(); 

  // Load the posts related to a given blog  
  // using a string to specify the relationship 
  context.Entry(blog).Collection("Posts").Load(); 
}
Run Code Online (Sandbox Code Playgroud)

当然Find,如果该实体已经被上下文加载,则立即返回而不向商店发出请求.

  • 此方法使用"查找",因此如果实体存在,则实体本身不会往返数据库.但是,你将为每个你正在"加载"的关系进行往返,而与"包含"的`SingleOrDefault`组合一起加载所有内容. (25认同)
  • 请注意你的帖子的参考:https://msdn.microsoft.com/en-us/data/jj574232.aspx#explicit (4认同)
  • 不是1:m关系,而是多种关系.每次调用`Load`函数时,都应该在调用返回时填充关系.因此,如果多次调用"Load"多次关系,每次都会有一次往返.即使对于单个关系,如果`Find`方法没有在内存中找到实体,它会进行两次往返:一次用于"Find",第二次用于"Load".但据我所知,`Include``SingleOrDefault`方法一次性获取实体和关系(但我不确定) (2认同)