14

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

给定一个模型类,例如:

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

Person 类不应该知道它的孩子是如何加载的……还是应该知道?当然,它应该控制何时填充属性?

您是否有一个将 Person 与其子集合耦合在一起的存储库,或者您是否会使用不同的方法,例如使用延迟加载类 - 即使这样,我也不希望延迟加载类在我的模型架构中模糊。

如果首先请求一个人然后是它的子项(即在此实例中不是延迟加载)或以某种方式延迟加载,您将如何处理性能。

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

4

7 回答 7

14

最好的延迟加载是避免它;)线程安全是您必须处理的直接问题。我不知道我有多少次看到具有 8 个 cpu 内核的生产系统对使用的每个延迟加载模式运行 8 次延迟加载。至少在服务器启动时,所有服务器内核都倾向于在同一个地方结束。

如果可以的话,让一个 DI 框架为您构建它。如果你不能,我仍然更喜欢显式构造。所以各种AOP魔法根本不跟我切,去类外显式构造吧。不要将它放在 person 类中,只需创建一个以正确方式构造对象的服务。

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

于 2009-02-07T16:47:32.647 回答
4

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

那里还有更详细的博客文章的链接...

于 2009-02-07T17:14:36.320 回答
1

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

于 2009-02-07T17:01:10.030 回答
1

您可以使用虚拟代理模式以及观察者模式。这会给你延迟加载,而 Person 类没有关于如何加载 Children 的明确知识。

于 2009-02-07T17:35:19.167 回答
0

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

于 2009-02-07T16:39:57.797 回答
0

我刚刚在这里问了一个相关的问题,但它在不变性和线程安全方面更重要。很多很好的答案和评论。您可能会发现它很有用。

于 2009-03-18T02:56:44.040 回答
0

这是一个使用代理模式实现延迟加载的示例

将与您的其余模型一起使用的 Person 类。Children 被标记为虚拟,因此可以在 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 并将执行延迟加载。您还可以使用布尔值来检查它是否已经加载,而不是检查 Children == 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 的接口并通过服务访问它。

于 2014-01-31T02:01:02.007 回答