ASP.MVC: Репозиторий, который отражает IQueryable, но не Linq к SQL, DDD, Как подвергнуть сомнению

Если Ваш друг имеет привычку нажатие ^A для получения до начала строки в ударе, он находится в для некоторых неожиданностей, так как ^A экранная привязка командной клавиши. Обычно я заканчиваю с замороженным экраном, возможно из-за некоторой случайной клавиши, которую я нажал, после ^A:-)

В тех случаях я пробую

^A s, и ^A q блокируют/разблокируют терминал, прокручивающий

для фиксации этого. Для движения в начало строки в экранируют сочетание клавиш, ^A a

12
задан Ruben Bartelink 29 August 2011 в 21:36
поделиться

2 ответа

Попробуйте что-то вроде этого:

public class AnnouncementCategory : //...
{
    public int ID { get; set; }
    public string Name { get; set; }
}

.. и в вашем репозитории:

public IQueryable<AnnouncementCategory> GetAnnouncementCategories()
{
    return from ac in this._dc.AnnouncementCategories
           let announcements = this.GetAnnouncementsByCategory(ac.ID)
           select new AnnouncementCategory
           {
               ID = ac.ID,
               Name = ac.Text,
               Announcements = new LazyList<Announcement>(announcements)
           };
}

private IQueryable<Announcement> GetAnnouncementsByCategory(int categoryID)
{
    return GetAnnouncements().Where(a => a.Category.ID == categoryID);
}

Таким образом, вместо проецирования в анонимный тип, я проецирую в новый экземпляр моего Класс AnnouncementCategory . Вы можете игнорировать функцию GetAnnouncementsByCategory , если хотите, она используется для цепочки коллекции связанных объектов Announcement для каждой категории, но таким образом, чтобы их можно было лениво загружать с помощью IQueryable ( т.е. когда я do в конечном итоге вызываю это свойство, мне не нужно вызывать всю коллекцию. Я могу сделать больше LINQ для этого для фильтрации).

8
ответ дан 2 December 2019 в 04:02
поделиться

Предполагая, что ваши классы LINQ to SQL (L2S) создаются автоматически и отражают вашу базовую базу данных, краткий ответ: не раскрывайте IQueryable ни для одного из ваших классов L2S - это будет a Leaky Abstraction .

Немного более длинный ответ:

Весь смысл репозиториев заключается в том, чтобы скрыть доступ к данным за абстракцией, чтобы вы могли заменять или изменять свой код доступа к данным независимо от вашей модели домена . Это будет невозможно, если вы основываете интерфейс репозитория на типах, определенных в конкретной реализации (ваш компонент доступа к данным на основе L2S (DAC)) - даже если вы можете предоставить новую реализацию своего интерфейса репозитория, вам потребуется сослаться на ваш L2S DAC. Это не сыграло бы особенно хорошо, если бы вы внезапно решили переключиться на LINQ to Entities, или служба хранилища таблиц Azure.

Объекты домена следует определять технологически нейтральным образом. Лучше всего это делать в виде простых старых объектов C # (POCO).

Кроме того, предоставление IQueryable дает вам возможность выполнять проекции. Это может показаться привлекательным, но на самом деле довольно опасно в контексте DDD.

В DDD мы должны проектировать объекты домена таким образом, чтобы они инкапсулировали логику домена и обеспечивали все инварианты.

В качестве примера рассмотрим концепцию сущности. (не объект LINQ to Entitities, а объект DDD). Сущности почти всегда идентифицируются постоянным идентификатором, поэтому один общий инвариант состоит в том, что идентификатор должен быть определен . Мы могли бы написать базовый класс Entity следующим образом:

public abstract class Entity
{
    private readonly int id;

    protected Entity(int id)
    {
        if(id <= 0)
        {
            throw new ArgumentOutOfRangeException();
        }
        this.id = id;
    }

    public int Id
    {
        get { return this.id; }
    }
}

Такой класс точно обеспечивает соблюдение своих инвариантов (в данном случае идентификатор должен быть положительным числом). Может быть много других, больше доменных инвариантов, реализованных в определенных классах, но многие из них, скорее всего, будут расходиться с концепцией проекции: вы можете определить проекцию, которая пропускает определенные свойства (например, ID), но она выйдет из строя во время выполнения, поскольку значения по умолчанию для типов (например, 0 для int) будут вызывать исключения.

Другими словами, даже если вам нужны только определенные свойства объекта домена, будет иметь смысл только гидратировать его полностью, потому что это единственный способ удовлетворить его инварианты.

В любом случае, если вы часто обнаруживаете, что вам нужно выбирать только определенные части ваших объектов домена, это может быть потому, что они нарушают единую ответственность Принцип. Возможно, было бы лучше разделить класс домена на два или более классов.

В заключение, раскрытие IQueryable звучит как очень привлекательная стратегия, но с текущей реализацией L2S это приведет к утечкам абстракций и анемичным доменным моделям.

В следующей версии Entity Framework мы должны получить поддержку POCO, так что это может нас ближе к этой цели. Однако, насколько мне известно, этот счет еще не решен.


Для более подробного обсуждения очень похожей темы см. IQueryable - это тесная связь .

29
ответ дан 2 December 2019 в 04:02
поделиться
Другие вопросы по тегам:

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