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

时间:2009-02-07 16:33:48

标签: c# architecture coding-style lazy-loading methodology

我见过很多延迟加载的例子 - 您的选择是什么?

给出一个模型类,例如:

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

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

你是否有一个将Person与其子集相结合的存储库,或者你会使用不同的方法,例如使用lazyload类 - 即使这样,我也不希望我的lazyload类模糊模型架构。

如果首先请求Person,然后是其子节点(即在此实例中不是延迟加载)或以某种方式延迟加载,您将如何处理性能。

所有这些都归结为个人选择吗?

7 个答案:

答案 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的接口并通过服务访问它。