我见过很多延迟加载的例子 - 您的选择是什么?
给出一个模型类,例如:
public class Person
{
private IList<Child> _children;
public IList<Child> Children
{
get {
if (_children == null)
LoadChildren();
return _children;
}
}
}
Person类不应该知道它是如何装载它们的......或者它应该是什么?当然它应该控制何时填充属性?
你是否有一个将Person与其子集相结合的存储库,或者你会使用不同的方法,例如使用lazyload类 - 即使这样,我也不希望我的lazyload类模糊模型架构。
如果首先请求Person,然后是其子节点(即在此实例中不是延迟加载)或以某种方式延迟加载,您将如何处理性能。
所有这些都归结为个人选择吗?
答案 0 :(得分:14)
最好的延迟加载是避免它;)线程安全是你必须处理的直接问题。对于使用的每个延迟加载模式,我没有看到我经常看到有8个cpu内核的生产系统运行延迟加载8次的频率。至少在服务器启动时,所有服务器核心都倾向于在同一个地方结束。
如果可以,让DI框架为您构建它。如果你不能,我仍然喜欢明确的建设。因此,各种各样的AOP魔法根本就不会与我一起切割,在课堂外进行明确的构建。不要把它放在person类中,只需创建一个以正确方式构造对象的服务。
介绍“魔术”图层或多或少透明地执行这些操作似乎就像一个好主意,但我还没有遇到没有不可预见和有问题后果的实现。
答案 1 :(得分:4)
您可以使用我在此处讨论过的Lazy<T>
课程:
What is the proper way to inject a data access dependency for lazy loading?
还有更详细的博客帖子链接......
答案 2 :(得分:1)
我谈到了用于完成延迟加载的解决方案here
答案 3 :(得分:1)
您可以使用Virtual Proxy模式以及Observer pattern。这将为您提供延迟加载,而Person类没有明确知道子如何加载。
答案 4 :(得分:0)
我认为这是正是最好由AOP处理的问题(例如,PostSharp)。将您的延迟加载作为一个方面,然后使用它来装饰您想要懒惰加载的任何属性。免责声明:没试过;只是认为它应该工作。
答案 5 :(得分:0)
我刚刚问了一个相关的问题here,但是它的重要性在于不变性&amp;线程安全大头钉。很多好的答案和评论。您可能会发现它很有用。
答案 6 :(得分:0)
以下是使用代理模式实现延迟加载的示例
将与其他模型一起使用的Person类。子项被标记为虚拟,因此可以在PersonProxy类中重写。
public class Person {
public int Id;
public virtual IList<Child> 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<Child> GetChildrenForPerson(int personId) {
// Return your list of children from the database
}
}
与您的存储库一起使用的PersonProxy类。这继承自Person并将执行延迟加载。您还可以使用布尔值来检查它是否已经加载,而不是检查子项是否== null。
public class PersonProxy : Person {
private PersonRepository _personRepository = new PersonRepository();
public override IList<Child> 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的接口并通过服务访问它。