Ленивая загрузка - какой подход лучше? - PullRequest
14 голосов
/ 07 февраля 2009

Я видел множество примеров ленивой загрузки - какой у вас выбор?

Учитывая класс модели, например:

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

Класс Person не должен ничего знать о том, как загружаются его дочерние элементы .... или так? Конечно, он должен контролировать, когда заполняются свойства, или нет?

Будет ли у вас репозиторий, который связывает Person с его дочерней коллекцией, или вы используете другой подход, например, использование класса lazyload - даже тогда я не хочу размывать класс lazyload в моей модели архитектуры.

Как бы вы справились с производительностью, если сначала запросите Person, а затем его Children (то есть не ленивую загрузку в этом случае) или как-нибудь ленивую загрузку.

Все это сводится к личному выбору?

Ответы [ 7 ]

14 голосов
/ 07 февраля 2009

Лучшая ленивая загрузка - избегать;) Безопасность потока - это насущная проблема, с которой вам придется столкнуться. У меня нет подсчета того, как часто я видел, как производственные системы с 8 ядрами процессора запускают ленивую загрузку 8 раз для каждого используемого ленивого шаблона загрузки. По крайней мере, при запуске сервера все серверные ядра имеют тенденцию попадать в одни и те же места.

Позвольте DI-фреймворку создать его вместо вас, если можете. И если вы не можете, я все же предпочитаю явную конструкцию. Так что все виды магии АОП просто не режут это вместе со мной, идут на явную конструкцию вне класса. Не помещайте его в класс person, просто создайте сервис, который правильно создает объекты.

Представление "магических" слоев, которые более или менее прозрачно выполняют эти вещи , кажется хорошей идеей, но мне еще не приходилось сталкиваться с реализациями, которые не имеют непредвиденных и проблемных последствий.

4 голосов
/ 07 февраля 2009

Вы можете использовать класс Lazy<T>, о котором я говорил здесь: Как правильно внедрить зависимость доступа к данным для отложенной загрузки?

Там также есть ссылка на более подробный пост в блоге ...

1 голос
/ 07 февраля 2009

Вы можете использовать шаблон Virtual Proxy вместе с шаблоном Observer . Это дало бы вам ленивую загрузку без явного знания класса Person о том, как загружаются дети.

1 голос
/ 07 февраля 2009

Я говорил о решении, которое я использую для выполнения отложенной загрузки здесь

0 голосов
/ 31 января 2014

Вот пример реализации отложенной загрузки с использованием шаблона Proxy

Класс 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);

Конечно, вы можете использовать PersonProxy в интерфейсе к PersonRepository и получать к нему доступ через службу, если не хотите вызывать PersonRepository напрямую.

0 голосов
/ 18 марта 2009

Я только что задал связанный вопрос здесь , но он оказался более тяжелым с точки зрения неизменности и безопасности потоков. Много хороших ответов и комментариев. Вы можете найти это полезным.

0 голосов
/ 07 февраля 2009

Я думаю, что точно - это проблема, которая лучше всего решается АОП (например, PostSharp). Имейте свою ленивую загрузку как аспект и затем используйте это, чтобы украсить любое свойство, которое вы хотите загружать лениво. Отказ от ответственности: не пробовал это; просто думаю, что должно работать.

...