#design-patterns
#шаблоны проектирования
Вопрос:
ORM часто сопоставляют отношения «один ко многим», такие как:
class Parent {
IList<Child> Children { get; set; }
}
Проблема в том, что в репозитории у вас может быть:
GetChildrenOfParent(int parentID) {
from c in Children...
return children;
}
Теперь у вас есть два места для «получения» дочерних элементов. Если вы хотите что-то добавить, например, возможно, возвращать только дочерние элементы, у которых нет флага deleted, у вас может быть:
GetChildrenOfParent(int parentID) {
from c in Children..
where not deleted
return children;
}
или
class Parent {
IList<Child> Children { get .... only get not deleted children; set; }
}
Вы понимаете, к чему я клоню? Теперь у вас есть два места, в которых можно выбрать выполнение процедуры получения. Кажется, что логичным местом для этой процедуры является репозиторий, но это означает, что:
foreach (var child in parent.Children)
больше не проходит через ваш «геттер», следовательно, вся идея о том, что ORM имеет сопоставление «один ко многим» таким образом, кажется неправильной?
Ответ №1:
Я не совсем уверен, в чем заключается ваш вопрос, но я действительно не вижу, где это «неправильно». Это сводится к выбору дизайна IMO. Вы хотите получить доступ к иерархическим данным (дочерним объектам) из каждого объекта. Если вы это сделаете и хотите загрузить эти данные при начальной выборке, то использование «один ко многим» позволяет сэкономить время (вы можете выбрать предварительную загрузку или отложенную загрузку).). В этом случае извлечение ваших данных в первом примере может быть полезным для вас. Вы можете использовать LINQ для фильтрации данных, чтобы возвращать только «не удаленные» результаты или «любой фильтр, который вам нужен», например:
IList<Child> list = parent.Children.Where(x => x.Deleted == false);
Лично мне нравится поддерживать его в чистоте и, когда я использую шаблон репозитория (в последнее время я становлюсь большим поклонником шаблона ActiveRecord). Я предпочитаю отделить это от собственного вызова метода. Вы могли бы добавить вызов репозитория в дочерние элементы имени свойства, но тогда, для меня, это похоже на то, что я пересекаю границы между иметь модель и где я использую эту модель.
Но выполнение этого таким образом иногда приводит к тому, что вы получаете целую кучу методов для выполнения базовой фильтрации или глупую кучу или перегрузки для управления случаями, когда вы хотите выбрать, скажем, «Удалено или нет» и «Мужчина или женщина» или просто «Удалено или нет».
Как я уже сказал, все сводится к выбору. Как вы хотите, чтобы ваше приложение росло, если вы считаете, что в итоге получаете список глупых перегрузок в репозитории, можете ли вы сделать его чище, чтобы будущие программисты могли понимать ваш код, меньше кода для управления, и это не влияет на производительность (или улучшает ее в идеале). В этом случае наличие тестов поможет вам провести рефакторинг без нарушения кода.
Не зацикливайтесь на «правильном» или «неправильном» способе выполнения действий.
Комментарии:
1. если вы выполните список = parent.children.where … вы использовали в своем примере, представьте, что произойдет, когда у вас будут сотни таких вызовов повсюду, и теперь вы хотите изменить его на where x.deleted amp;amp; x.возраст < 18. Суть методов получения или репозитория в том, что вы изменяете его только в одном месте, и это не нарушает никаких контрактов.
2. Именно поэтому я сказал, что предпочитаю содержать его в чистоте и помещать в собственный метод репозитория. Если вы знаете, что я действительно не уверен, о чем вы спрашиваете, но я возвращаюсь к своему первоначальному совету, выбирайте то, что подходит ВАМ и ВАШЕМУ приложению, не увязайте в том, что ваша интерпретация «наилучшей практики» говорит вам «правильно» или «неправильно». По личному опыту, попытка строго придерживаться того, что некоторые считают «правильным» или «неправильным», приводит к значительному замедлению прогресса или раздуванию вашего кода из-за перегрузок.
3. Если вам нужно будет использовать этот отфильтрованный запрос более чем в нескольких местах, тогда имеет смысл создать для него специальный метод, который поможет в обслуживании кода. Независимо от того, получаете ли вы доступ к этим результатам как к свойству вашего класса или нет, зависит от личного выбора того, как вы хотите моделировать свой домен.