我需要急切加载层次结构,以便我可以递归迭代它。在遍历树时,需要急切加载以防止多个数据库查询。似乎共识是你不能急于加载树的无限级别,所以我做了类似
的事情 var item= db.ItemHierarchies
.Include("Children.Children.Children.Children.Children")
.Where(x => x.condition == condition)
加载5个级别的孩子。这似乎完成了工作。我想知道这样做的缺点是什么?如果没有,那么理论上我可以在这里添加50级包含而不减慢速度吗?
答案 0 :(得分:2)
我建议您查看在为查询添加预先加载时生成的SQL。
var item= db.ItemHierarchies
.Include("Children")
.Include("Children.Children")
.Include("Children.Children.Children")
.Include("Children.Children.Children.Children")
.Include("Children.Children.Children.Children.Children")
var sql = ((System.Data.Objects.ObjectQuery) item).ToTraceString()
// http://visualstudiomagazine.com/blogs/tool-tracker/2011/11/seeing-the-sql.aspx
您会发现SQL很快变得非常庞大和复杂,并且可能会对性能产生严重影响。您最好将您急切的加载限制为您确定需要的数据,并考虑对某些相关实体使用显式加载 - 特别是如果您正在使用连接实体,在这种情况下您可以显式加载集合属性当他们需要的时候。
另请注意,您可能不需要多个单独的包含。例如,以下内容需要单独包含因为它们正在处理根的单独属性(Widgets和Spanners)。
var item= db.ItemHierarchies
.Include("Widgets")
.Include("Spanners.Flanges")
但以下情况并非必要:
var item= db.ItemHierarchies
.Include("Widgets") //This isn't necessary.
.Include("Widgets.Flanges") //This loads both Widges and Flanges.
答案 1 :(得分:1)
假设你的根中有50个对象..每个级别有50个。
您最终可能会检索312500000个“胶囊”信息。
现在,有人可能会问:“那有什么问题?!”, 我的意思是,如果那是必要的,那么为什么不这样做..
规则#1:我们开发应该由人类使用的软件。
而事实是,没有人能够一眼就看到312500000条信息,并从中学习或总结出有益的东西。 (除了......它没有帮助他或她观看它)
规则#2:用户界面应该基于所需要的而不是可能的。
而且由于我们已经确定不需要显示312500000个数据胶囊,因此没有理由同时提供所有这些数据。
现在你可以站出来说 - 但我不关心用户界面,真的!我需要的是迭代这些数据以处理一些信息!
在这种情况下,您可能希望将结果保存在某处以备将来参考,但这意味着它是一个批处理作业..那么为什么不在它上面应用批处理作业规则..就像逐项处理它一样也可能如果需要,可以在更多机器之间分配它。
所以你看..无论你选择哪条路,都没有理由这么做 (=什么是不良做法的定义。)
更新:
在阅读评论中有趣的问题之后,我想通过更多分析来更新这个答案:
决定什么是不良做法必须始终参考要实现的目标或系统中每个部分的作用。在目前的情况下(在阅读评论之后),已经或暗示数据存储实际上是对于与数据是应用程序“核心”的不同概念相对立的对象的持久媒介。
我们可以定义两种数据类型:
1)数据中心,用于以数据为中心的应用程序,如银行,CRM,ERP,网站或其他基于服务的解决方案。
VS
2)数据持久性介质,用作应用程序未处于活动状态时保存的数据,例如:任何简单的应用程序保存文件或任何游戏保存文件等。
主要区别在于,数据持久性介质仅在单个时间点由应用程序的单个实例访问。这意味着数据不会被许多实例共享。如果要共享数据 - 我们正在处理数据中心应用程序。
如果你的应用只需要一个数据持久性媒介 - 加载所有信息不能被认为是一种不好的做法 - 但你仍然需要确保你没有爆炸内存。在那个工作框架中,SQL Server可能不是您需要的或最好的工具。
在以数据为中心的应用程序的另一种情况下 - 我的原始答案仍然存在,因为为应用程序的每个实例提供所有信息将是一种不好的做法。