Я борюсь с проблемой, связанной с DDD, с Спецификациями, и я много читал в DDD, спецификациях и репозиториях.Спецификация шаблона в доменном дизайне
Однако есть проблема, если вы попытаетесь объединить все 3 из них, не нарушая ведомый домен. Это сводится к тому, как применять фильтры с учетом производительности.
Первые несколько очевидных фактов:
- Хранилища к полученному DataAccess/Infrastructure слой
- Доменные Модели представляют бизнес-логику и перейти к слою домена
- Модели доступа к данным представляют персистенции слой и перейдите к Уровень Persistance/Infrastructure/DataAccess
- Бизнес-логика переходит на доменный уровень
- Технические характеристики Business Logic, поэтому они также относятся к слою Domain.
- Во всех этих примерах ОРМ Framework и SQL Server используется внутри Repository
- ПЕРСИСТЕНТНОСТЬ Модели не могут просочиться в домене слоя
До сих пор так легко. Проблема возникает, когда/если мы пытаемся применить Спецификации к репозиторию и не нарушать шаблон DDD или проблемы с производительностью.
Возможные способы применения Технических характеристик:
1) Классический способ: Спецификации с использованием модели предметной области в домене уровне
применить традиционные спецификации шаблона, с помощью метода IsSatisfiedBy
, возвращая bool
и композитные спецификации для объединения нескольких спецификаций.
Это позволило нам сохранить спецификации в домене уровня, но ...
- Он должен работать с моделями домена, в то время как хранилище использует персистенции модели, которые представляют структуру данных слоя сохранения. Это легко исправить с использованием таких карт, как
AutoMapper
. - Однако проблема, которая не может быть решена: все спецификации должны выполняться в памяти. В больших таблицах/базах данных это означает, что огромное влияние, если вы должны перебрать все юридическое лицо, только чтобы отфильтровать один, которые отвечают Вашим требованиям
2) Технические характеристик с помощью Стойкости Модели
Это похоже до 1), но с использованием моделей устойчивости в спецификации. Это позволяет напрямую использовать Спецификацию как часть нашего предиката .Where
, который будет переведен в запрос (т. Е. TSQL), и фильтрация будет выполняться в хранилище Persistence (то есть SQL Server).
- Хотя это дает хорошие результаты, оно явно нарушает шаблон DDD. Наша модель Persistence просачивается в слой Domain, что делает слой домена зависимым от уровня Persistence, а не наоборот.
3) Как 2), но сделать спецификации Часть Persistence Layer
- Это не работает, потому что домен Layer должен ссылаться на спецификации. Он все равно будет зависеть от уровня сохранения.
- У нас была бы логика бизнеса внутри слоя Persistence. Который также нарушает DDD рисунка на
4) Мне нравится 3, но использовать абстрагировать характеристики как интерфейсы
Мы бы Спецификация интерфейсов в нашем домене слоя наших конкретных реализаций спецификации в Persistence Layer. Теперь наш слой домена будет взаимодействовать только с интерфейсами и не будет зависеть от уровня Persistence.
- Это по-прежнему нарушает № 2 из 3). У нас была бы бизнес-логика в плане сохранения, что плохо.
5) Перевести дерево Expression от модели предметной области в Persistence модели
Это, конечно, решает эту проблему, но это нетривиальная задача, но она будет держать спецификации внутри нашего домена слоя в то же время выгоды от оптимизация SQL, поскольку характеристика становится частью Хранилища, где положение и переводит в TSQL
Я пытался идти этот подход и есть несколько вопросов (форма боковых реализации):
- Нам нужно знать конфигурацию из Mapper (если мы ее используем) или сохранить нашу собственную систему сопоставления. Это может быть частично выполнено (чтение конфигурации Mapper) с помощью AutoMapper, но существуют дополнительные проблемы
- Это приемлемо для одного, где одно свойство модели A сопоставляется с одним свойством модели B. Сложнее, если типы различны (т.е. из-за типов сохраняемости, например, перечисления, которые сохраняются в виде строк или пар ключ/значение в другой таблице, и нам нужно делать преобразования внутри распознавателя.
- Это становится довольно сложным, если несколько полей отображаются в одно поле назначения. это не является проблемой для домена Model -> Постоянство Модель отображения
** 6) Query Builder, как API **
Последний из них делает какой-то API запросов, который передается в спецификацию и из которого слой репозитория/сдерживания будет генерировать дерево выражений, которое должно быть передано в .Where
, и которое использует интерфейс для объявления всех фильтруемых полей.
Я сделал несколько попыток в этом направлении, но не был слишком доволен результатами. Что-то вроде
public interface IQuery<T>
{
IQuery<T> Where(Expression<Func<T, T>> predicate);
}
public interface IQueryFilter<TFilter>
{
TFilter And(TFilter other);
TFilter Or(TFilter other);
TFilter Not(TFilter other);
}
public interface IQueryField<TSource, IQueryFilter>
{
IQueryFilter Equal(TSource other);
IQueryFilter GreaterThan(TSource other);
IQueryFilter Greater(TSource other);
IQueryFilter LesserThan(TSource other);
IQueryFilter Lesser(TSource other);
}
public interface IPersonQueryFilter : IQueryFilter<IPersonQueryFilter>
{
IQueryField<int, IPersonQueryFilter> ID { get; }
IQueryField<string, IPersonQueryFilter> Name { get; }
IQueryField<int, IPersonQueryFilter> Age { get; }
}
и в спецификации мы бы передать IQuery<IPersonQueryFilter> query
конструктору спецификации, а затем применить спецификации к нему при использовании или его сочетания.
IQuery<IGridQueryFilter> query = null;
query.Where(f => f.Name.Equal("Bob"));
мне не нравится этот подход, много, как это делает обработку сложных технических характеристик довольно трудно (как и или цепочки), и мне не нравится то, как и/или/не будет работать, особенно создание деревья выражений из этого «API».
Я ищу недель все через Интернет, прочитал десятки статей о DDD и спецификации, но они всегда обрабатывать только простые случаи, и не принимать во внимание работу, или они нарушают DDD шаблон.
Как вы решаете это в приложении реального мира, не занимаясь фильтрацией или утечкой памяти Стойкость к доменному слою?
Существуют ли какие-либо фреймворки, которые решают проблемы выше с помощью одного из двух способов (Query Builder, например, синтаксиса для деревьев выражений или транслятора дерева выражений)?
Я рад, что нашел ваш вопрос: у меня были ** именно те же вопросы и те же предложения об отделении моделей и шаблона спецификации! Я нашел это [ссылка] (http://enterprisecraftsmanship.com/2016/04/05/having-the-domain-model-separate-from-the-persistence-model/), где парень объясняет, что наличие отдельных моделей приносит немного больше чистоты для вашей модели, но принести много накладных расходов. Для него это не стоит. Я надеюсь, что эта статья была бы полезна :-) – Arcord
Демонстрация общих спецификаций с универсальным репозиторием EF, где spec используется как для фильтрации, так и для загрузки загружаемых данных: http://deviq.com/specification-pattern/ – ssmith