Ленивая Загрузка Набора - как получить объекты?

Я имею просто Класс, который предназначается, чтобы быть простым ПОСТЕПЕННО - он просто содержит данные. За одним исключением: Это содержит Набор Примечаний. Я хочу к ленивой загрузке этот набор так, чтобы я не выбирал Примечания на Страницах, которым не нужны они. Тупик для этого - это:

public class MyDTOClass 
{
    private ICollection<Note> _notes = null;

    public ICollection<Note> Notes
    {
        get
        {
            if(_notes == null)
            {
                // Get an INoteRepository and initialize the collection
            }
            return _notes;
        }
    }
}

Теперь, я задаюсь вопросом, как продолжить двигаться отсюда. Это - приложение MVC ASP.net, и я использую Внедрение зависимости для введения IRepositories в классах, которым нужны они, например, мои контроллеры. Но поскольку этим классом здесь, как предполагается, является действительно простой DTO, я отказываюсь ввести INoteRepository в него, также потому что вызывающая сторона не должна волноваться или заботиться о том, что это лениво загружается.

Таким образом, я думаю о наличии другого Класса в моей Модели, которая содержит INoteRepository.

public class MyDataAccessClass
{
    private INoteRepository _noteRepo;

    // Inject is part of Ninject and makes sure I pass the correct
    // INoteRepository automatically
    [Inject]
    public MyDataAccessClass(INoteRepository noteRepository)
    {
        _noteRepo = noteRepository;
    }

    public IEnumerable<Note> GetNotes(int projectId)
    {
        return _noteRepo.GetNotes(projectId);
    }
}

Это работало бы, конечно, но интересно, является ли это корректной архитектурой? Я связываю простой DTOClass с другим классом Доступа к данным и возможно также к моему механизму DI (поскольку я должен создать Экземпляр класса Доступа к данным в методе считывания Примечаний).

Вы сделали бы это по-другому? Существует ли лучший способ сделать это, также имея в виду, что я уже использую Ninject?

Я предполагаю, что это не ПОСТЕПЕННО или DTO больше, поскольку он теперь содержит логику, но это хорошо. Я хочу, чтобы это появилось как ПОСТЕПЕННО внешней вызывающей стороне, таким образом, мне нравится иметь Свойство "Примечания", а не методы как "GetNotesForProject" на этом или других классах.

Мое текущее решение действительно ужасно, поскольку я должен получить Ядро Ninject от своего MvcApplication и использовать его для вращения класса ProjectDataProvider, который принимает INoteRepository, это - конструктор, чтобы избежать необходимости помещать INoteRepository где-нибудь в мой "DTO" - Класс:

public ICollection<Note> Notes
{
    get
    {
        if(_notes == null)
        {
            var app = HttpContext.Current.ApplicationInstance as MvcApplication;
            if (app == null)
             throw new InvalidOperationException("Application couldn't be found");
            var pdp = app.Kernel.Get<ProjectDataProvider>();
            _notes = new List<Note>(pdp.GetNotes(Id));
        }
        return _notes;
    }
}

Править: Открытый щедрость. Давайте проигнорируем терминологию "ПОСТЕПЕННО" и "DTO", я осуществлю рефакторинг соответственно. Таким образом, это о: Как Ленивая Загрузка должна кодировать взгляд в такой ситуации и может/должна, я стараюсь не передавать INoteRepository в MyDTOClass?

7
задан Michael Stum 8 January 2010 в 23:11
поделиться

7 ответов

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

Как насчет чего-то вроде этого:

public class MyDTOClass
{
    private ICollection<Note> _notes = null;

    public ICollection<Note> Notes
    {
        get
        {
            if (_notes == null)
            {
                if (notesValueProvider == null)
                    throw new InvalidOperationException("ValueProvider for notes is invalid");
                _notes = notesValueProvider();
            }
            return _notes;
        }
    }

    private Func<ICollection<Note>> notesValueProvider = null;

    public MyDTOClass(Func<ICollection<Note>> valueProvider)
    {
        notesValueProvider = valueProvider;
    }
}

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

public class Repository
{
    public MyDTOClass GetData()
    {
        MyDTOClass dto = new MyDTOClass(FetchNotes);
        return dto;
    }

    public ICollection<Note> FetchNotes()
    {
        return new List<Note>(200);
    }
}

для тебя?

8
ответ дан 6 December 2019 в 08:43
поделиться

Если вы можете подождать .Net 4 (т.е. вы еще не в производстве), то Lazy(of T) - это новая функция Lazy Loading в .Net фреймворке. http://msdn.microsoft.com/en-us/library/dd642331(VS.100).aspx

7
ответ дан 6 December 2019 в 08:43
поделиться

Вы нарушаете все назначение DTO, когда пытаетесь добавить к ним логику ленивой загрузки. Я думаю, что у вас должны быть два отдельных объекта: один с Notes, а другой -- без них.

.
2
ответ дан 6 December 2019 в 08:43
поделиться
[

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

] [

]Чтобы вы могли написать в вашем сущностном классе что-то вроде:[

] [
public class Monster
{
    public ReadOnlyCollection<Victim> _victims;
    public ReadOnlyCollection<Victim> Victims
    {
        get
        {
            if (this._victims == null) // Note: Thread-Safety left out for brevity
            {
                this._victims = VictimRepository.Instance.GetVictimsForMonster(this);
            }

            return this._victims;
        }
    }
}
] [

]Это действительно решило все головные боли для меня.[

] [

]Репозиторий должен быть реализован таким образом, чтобы он всегда знал, что делать с данными.[

] [

]Помните, что одна реализация репозитория, например, будет получать данные из базы данных, в то время как другая может получать их из веб-сервиса. Из-за отсутствия связи, модуль реализации репозитория легко заменяется, а любое взаимодействие с данными даже произвольно цепляется. [

] [

]Если у вас есть сценарий, в котором вы говорите "но репозиторий не может быть однокнопочным, потому что у меня есть сложный сценарий, в котором я, например, получаю доступ к нескольким источникам данных, и это зависит от фактического экземпляра []Monster[], откуда можно получить []Victim[]s", то я говорю, что вы должны создать такую реализацию репозитория, которая знает все источники данных и отслеживает, откуда приходят и куда уходят экземпляры сущностей, и так далее. ...[

] [

]Если вам кажется, что этого подхода недостаточно для POCO, то вы должны создать другой свободно связанный Уровень Бизнес Логики, который обёртывает или извлекает из сущности POCO и реализует там взаимодействие с репозиторием.[

] [

]Надеюсь, я смогу дать подсказку в направлении, которое кажется подходящим для вас и для любого другого человека. Я действительно верю, что это священный грааль для многослойной/уровневой разработки. Не стесняйтесь обсуждать это дальше.[

]
1
ответ дан 6 December 2019 в 08:43
поделиться
[

] В качестве параметра в INoteRepository можно использовать свойство Notes. Таким образом, код вызова может быть передан в корректном экземпляре INoteRepository.[

].
0
ответ дан 6 December 2019 в 08:43
поделиться

Другой вариант - использовать прокси, которые наследуют от объектов, которые вы хотите получить (после проведения некоторых объектов-реляционных материалов, таких как NHIBERNATE).

Это обеспечивает незнакомое значение настойчивости, поддерживая код доступа к данным отдельно от модели домена:

public class MyLazyDTOClass: MyDTOClass {   

    // Injected into the constructor by the MyDtoClass repository
    private INoteRepository noteRepository;        

    public ICollection<Note> Notes {
        get {
            if(base.Notes == null) {
                base.Notes = noteRepository.GetNotes(projectId);
            }
            return base.Notes;
        }
    }
}

MyDToclassRepository объявляет базовый объект в качестве возврата, но возвращает ленивый объект вместо этого:

public MyDTOClassRepository {
    public MyDTOClass GetMyDTOClass(int id) {
        // ... Execute data access code to obtain state ...
        return new MyLazyDTOClass(this, state);
    }
}

MyDToclass Потребители не нужно знать, что они имеют дело с прокси, и они не должны взаимодействовать с репозиториями (за исключением того, что любой класс делает первоначальный звонок курса).

2
ответ дан 6 December 2019 в 08:43
поделиться

Вы не можете добиться независимости от вашего репозитория, если вы ленивы от нее Отказ Вы можете сохранить его на расстоянии ARM, используя обратный вызов или прокси или позволить Nibernate сделать грязную работу для вас, но ваш DTO должен получить доступ к репозитории для загрузки заметок.

Ваша главная цель, по-видимому, «я хочу, чтобы это было похоже на поговорку на внешний абонент, поэтому я люблю иметь свойство« заметки », а не методы, такие как« getnotesforProject »на этом или другим классам. Разве вы не можете достичь этого с инъекцией Ninject и Constructor? Как только вы настроите Ninject, вы можете вызвать Kernel.get (), чтобы получить новый экземпляр, который не будет подвергать ссылку на ваш репозиторий.

1
ответ дан 6 December 2019 в 08:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: