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

发布于 2024-07-12 21:45:10 字数 682 浏览 6 评论 0原文

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

例如,给定一个模型类:

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

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

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

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

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

I have seen numerous examples of lazy loading - what's your choice?

Given a model class for example:

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

The Person class should not know anything about how it's children are loaded .... or should it? Surely it should control when properties are populated, or not?

Would you have a repository that couples a Person together with its children collection or would you use a different approach, such as using a lazyload class - even then, I don't want a lazyload class blurring in my model architecture.

How would you handle performance if first requesting a Person and then its Children (i.e. not lazy loading in this instance) or somehow lazy loading.

Does all this boil down to personal choice?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

橙幽之幻 2024-07-19 21:45:21

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

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

Here is an example implementing lazy loading using the Proxy pattern

The Person class that would live with the rest of your models. Children is marked as virtual so it can be overridden inside the PersonProxy class.

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

The PersonRepository class that would live with the rest of your repositories. I included the method to get the children in this class but you could have it in a ChildRepository class if you wanted.

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
    }
}

The PersonProxy class that lives with your repositories. This inherits from Person and will do the lazy loading. You could also use a boolean to check if it has already been loaded instead of checking to see if 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; }
    }
}

You could use it like so

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

Of course you could have PersonProxy take in an interface to the PersonRepository and access it all through a service if you don't want to call the PersonRepository directly.

a√萤火虫的光℡ 2024-07-19 21:45:20

我刚刚问了一个相关的问题 这里,但它更注重不变性和一致性。 螺纹安全大头钉。 很多好的答案和评论。 您可能会发现它很有用。

I just asked a related question here, but it was heavier on the Immutability & Thread Safety tack. Lots of good answers and comments. You may find it useful.

漆黑的白昼 2024-07-19 21:45:18

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

I'm thinking that this is precisely the kind of problem that is best handled by AOP (e.g., PostSharp). Have your lazy loading as an aspect and then use it to decorate whatever property you want to be loaded lazily. Disclaimer: haven't tried it; just thinking that it should work.

诺曦 2024-07-19 21:45:15

您可以使用 虚拟代理 模式以及 观察者模式。 这将为您提供延迟加载,而 Person 类不需要明确了解 Children 的加载方式。

You can use the Virtual Proxy pattern, along with the Observer pattern. This would give you lazy loading without the Person class having explicit knowledge about how Children are loaded.

[浮城] 2024-07-19 21:45:14

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

I talked about a solution I use to accomplish lazy loading here

素手挽清风 2024-07-19 21:45:12

最好的延迟加载就是避免它;)线程安全是您必须立即处理的问题。 我不知道有多少次我看到具有 8 个 cpu 核心的生产系统对正在使用的每个延迟加载模式运行延迟加载 8 次。 至少在服务器启动时,所有服务器核心都倾向于出现在相同的位置。

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

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

The best lazy loading is avoiding it ;) Thread safety is an immediate problem you'll have to handle. I have no count of how often I have seen production systems with 8 cpu cores run lazy loading 8 times for every single lazy loading pattern in use. At least on server startups all server cores have a tendency to end up in the same places.

Let a DI framework construct it for you instead, if you can. And if you cannot, I still prefer explicit construction. So all sorts of AOP magic simply do not cut it with me, go for explicit construction outside the class. Don't put it inside the person class, just make a service that constructs the objects in the proper manner.

Introducing "magic" layers that more or less transparently do these things seem like a nice idea, but I have yet to come across implementations that do not have unforseen and problematic consequences.

缱绻入梦 2024-07-19 21:45:12

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

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

You can use the Lazy<T> class I talked about here :
What is the proper way to inject a data access dependency for lazy loading?

There is also link to a more detailed blog post there...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文