Репозитории и игнорирование постоянства снова

Вот чем я занимаюсь.

У меня есть общий класс репозитория Repository<TKey, TValue>. Он имеет обычные методы шаблона репозитория.

Каждый репозиторий принимает IContext<TKey, TValue> в своем конструкторе, который обеспечивает постоянство для репозитория.

У меня есть специализированные репозитории, которые состоят из общего репозитория, а затем методов, адаптированных к действиям репозитория, специфичным для специализированного объекта. Итак, если бы у меня был специализированный репозиторий для объектов Kitten, у него были бы методы ClimbTree (вероятно, берущие объект дерева), но не метод BuryBone (кость кости). Дело в том, что я делаю плохо, это создает ассоциацию между котенком и его деревом, которое необходимо сохранить. void CleanWhiskers() может быть более простым примером. Это приводит к тому, что усы котят становятся чистыми.

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

Я начал с немного уродливых методов в репозитории для создания дочерних объектов. Таким образом, репозиторий котенка будет иметь метод CreateFurBall(), который будет добавлять объект FurBall в коллекцию FurBall котенка И добавлять Furball в репозиторий FurBall для сохранения (фактически тот же объект).

Теперь я перешел на систему, в которой у меня есть что-то вроде ObservableCollection, который уведомляет свой родительский репозиторий при добавлении POCO. Так что я могу просто создать пушистого комка POCO и добавить его в коллекцию, которая затем будет автоматически зарегистрирована в репозитории пушистого комка.

Во-первых, я реализую nHibernate в контекстах, я думаю, что это довольно хорошо отображается. Это действительно открытый вопрос, для тех, кто уже шел по этому пути раньше, видите ли вы что-нибудь, что заставляет вас воскликнуть: «СТОП!!»


person Ian    schedule 17.02.2011    source источник


Ответы (4)


Нельсон прав.

Я думаю, что может возникнуть путаница между двумя способами создания пушистых комков. Если котенок хранится в базе данных с тремя пушистыми комками, то при его извлечении из базы котенку должны быть введены его пушистые данные, а коллекция пушистых комков должна быть инициализирована из пушистых данных.

Когда приложение хочет добавить пушистого комка к котенку, пушистый комок должен находиться рядом с котенком через Kitten.CreateFurBall(). Здесь я делаю предположение, что пушистый комок принадлежит котенку, а пушистый комок не является общим для других котят. Если пушистый комок достаточно сложен, вам может понадобиться абстрагировать его создание от FurballFactory, на которую котенок имеет ленивую ссылку.

Что касается создания объекта Kitten, вероятно, лучше всего с этим справиться, имея ссылку на KittenFactory в вашем KittenRepository, которая принимает dto для котенка и создает из него котенка.

Самая большая проблема, которую вы продемонстрировали, связана с методом Kitten.BuryBone(Bonebone). Котята не зарывают кости. Собаки делают.

person steinberg    schedule 17.02.2011
comment
Все отличные комментарии, спасибо. Да, BuryBone будет щенячьей операцией. Я думаю, что мои примеры были немного неправильными, специализированный репозиторий будет отвечать исключительно за сохранение объектов, но будет налагать определенные ограничения. Итак, если я удалю котенка, он удалит связанные с ним данные, пушистые комки и все из других репозиториев. Теперь это становится яснее в моей голове. - person Ian; 17.02.2011
comment
Да, похоже, ты понимаешь. - person steinberg; 17.02.2011

Я должен был подумать, что такие методы, как ClimbTree(), BuryBone(), CreateFurBall() и CleanWhiskers(), относятся к объектам домена, а не к репозиториям.

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

person Ian Nelson    schedule 17.02.2011

Возможно, я немного не по теме, но я просто хотел добавить свои пять копеек по поводу шаблона репозитория.

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

Я довольно часто использую Entity Framework и LINQ to SQL. Чтобы выводить из них результаты, мне нужно, чтобы LINQ работал с IQueryable<entity>, чтобы разбиение по страницам происходило на уровне базы данных. Мне не нравится выставлять IQueryable за пределы моего репозитория. Потому что что, если когда-нибудь мой репозиторий нужно будет переписать, и хранилище данных больше не сможет использовать IQueryable? Поэтому вместо того, чтобы возвращать это из моего репозитория:

IQueryable<entity> GetEntities();

... и пейджинг результатов в моем контроллере или в другом месте моего приложения. Вместо этого я делаю это:

IEnumerable<entity> GetEntities_byPage(int page);

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

Я думаю, что ваши репозитории должны возвращать некоторые довольно адаптированные данные, а не просто дамп необработанных данных, который ваш контроллер должен очистить (обычно после загрузки всего в память, YECK!).

person Chev    schedule 17.02.2011
comment
Интересный материал, я прочитал сообщение в блоге о плюсах и минусах раскрытия IQueryable в репозитории. Аргумент против заключался в том, что это смешивает опасения, а за то, что это чертовски полезно. В данный момент я пытаюсь его поддержать, мне просто нужно выяснить, как это сделать в моем невежественном решении с настойчивостью :) - person Ian; 18.02.2011

В прошлом я использовал шаблон репозитория в качестве очень тонкого посредника между поставщиком постоянства и объектами данных — каждый репозиторий содержит только очень общие методы (т. е. обычно Add/Update/Delete).

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

person BrokenGlass    schedule 17.02.2011