延迟加载 – 最好的方法是什么?

我见过很多懒加载的例子 – 你有什么选择?

给定一个模型类,例如:

public class Person { private IList _children; public IList Children { get { if (_children == null) LoadChildren(); return _children; } } } 

Person类不应该知道它是如何被装载的……或者它应该是什么? 当然它应该控制何时填充属性?

您是否有一个将Person与其子集合耦合在一起的存储库,或者您是否会使用不同的方法,例如使用lazyload类 – 即便如此,我也不希望在我的模型体系结构中使用lazyload类模糊。

如果首先请求一个Person然后它的子节点(即在这个例子中不是延迟加载)或者以某种方式延迟加载,你将如何处理性能。

这一切都归结为个人选择吗?

最好的延迟加载是避免它;)线程安全是你必须处理的直接问题。 我不知道我经常看到有8个CPU内核的生产系统为每个使用的延迟加载模式运行延迟加载8次。 至少在服务器启动时,所有服务器核心都倾向于在相同的位置结束。

如果可以的话,让DI框架为您构建它。 如果你不能,我仍然喜欢明确的建设。 因此,各种各样的AOP魔法根本就不会与我一起切割,在课堂外进行明确的构建。 不要把它放在person类中,只需创建一个以正确方式构造对象的服务。

引入“魔术”层或多或少地透明地做这些事情似乎是一个好主意,但我还没有遇到没有不可预见和有问题的后果的实现。

您可以使用我在这里谈到的Lazy类: 为延迟加载注入数据访问依赖项的正确方法是什么?

还有链接到更详细的博客post……

我谈到了我用来完成延迟加载的解决方案

您可以使用虚拟代理模式以及观察者模式 。 这将为您提供延迟加载,而Person类不具有有关如何加载Children的明确知识。

我认为这恰恰是AOP最好处理的问题(例如,PostSharp)。 将您的延迟加载作为一个方面,然后使用它来装饰您想要懒惰加载的任何属性。 免责声明:没试过; 只是认为它应该工作。

我刚刚在这里问了一个相关的问题,但在Immutability&Thread Safety方面它更重要。 很多好的答案和评论。 你可能会发现它很有用。

以下是使用代理模式实现延迟加载的示例

将与其他模型一起使用的Person类。 子项被标记为虚拟,因此可以在PersonProxy类中重写它。

 public class Person { public int Id; public virtual IList Children { get; set; } } 

PersonRepository类将与其他存储库一起使用。 我包含了获取此类中的子项的方法,但如果需要,可以在ChildRepository类中使用它。

 public class PersonRepository { public Person FindById(int id) { // Notice we are creating PersonProxy and not Person Person person = new PersonProxy(); // Set person properties based on data from the database return person; } public IList GetChildrenForPerson(int personId) { // Return your list of children from the database } } 

与您的存储库一起使用的PersonProxy类。 这inheritance自Person并将执行延迟加载。 您还可以使用布尔值来检查它是否已经加载,而不是检查是否有孩子== null。

 public class PersonProxy : Person { private PersonRepository _personRepository = new PersonRepository(); public override IList Children { get { if (base.Children == null) base.Children = _personRepository.GetChildrenForPerson(this.Id); return base.Children; } set { base.Children = value; } } } 

你可以像这样使用它

 Person person = new PersonRepository().FindById(1); Console.WriteLine(person.Children.Count); 

当然,如果您不想直接调用PersonRepository,您可以让PersonProxy接受PersonRepository的接口并通过服务访问它。