Рекомендации по проектированию объектов сопоставления Linq to SQL
Я надеюсь, что заголовок и следующий текст понятны, я не очень знаком с правильными терминами, поэтому, пожалуйста, исправьте меня, если я что-то не так. Я использую Linq ORM впервые и мне интересно, как решить следующие вопросы.
Скажем, у меня есть две таблицы БД:
User
----
Id
Name
Phone
-----
Id
UserId
Model
Генератор кода Linq создает несколько классов сущностей.
Затем я пишу свои собственные классы и интерфейсы, которые обертывают эти классы Linq:
class DatabaseUser : IUser
{
public DatabaseUser(User user)
{
_user = user;
}
public Guid Id
{
get { return _user.Id; }
}
... etc
}
Все идет нормально.
Теперь достаточно просто найти пользователей телефонов из Phones.Where(p => p.User = user)
но, конечно же, пользователям API не нужно писать свои собственные запросы Linq для получения данных, поэтому я должен заключить этот запрос в функцию или свойство где-нибудь.
Таким образом, вопрос в том, добавите ли вы свойство Phones в IUser или нет?
Другими словами, должен ли мой интерфейс специально моделировать объекты моей базы данных (в этом случае телефоны не принадлежат IUser), или они на самом деле просто предоставляют набор функций и свойств, которые концептуально связаны с пользователем (в этом случае он делает)?
Кажется, есть недостатки в обоих взглядах, но мне интересно, существует ли стандартный подход к проблеме. Или просто какие-нибудь общие слова мудрости, которыми вы могли бы поделиться.
Моей первой мыслью было использовать методы расширения, но на самом деле это не работает в этом случае.
4 ответа
У меня был ужасный опыт, когда я пытался абстрагировать сущности LINQtoSQL за интерфейсами. Это было некоторое время назад, но по памяти основная проблема заключалась в том, что это полностью разрушает ассоциации. Например, если у вас есть Customer
-> Order
отношения, вы заканчиваете тем, что выставляете это как ICustomer
, с коллекцией IOrder
с, что означает, что Customer
должен сделать какое-то неловкое отображение, чтобы наложить его внутреннюю коллекцию Order
объекты как IOrder
s.
Тогда вы должны предположить, что когда IOrder
передается обратно, что мы можем привести его к Order
, В противном случае LINQtoSQL не сможет справиться с этим, но тогда это лишит смысла наличие интерфейса в первую очередь.
Я настоятельно рекомендую вам не пытаться абстрагировать классы сущностей слишком сильно, LINQtoSQL фактически не вкладывает в них никакого волшебства, DataContext обрабатывает их жизненный цикл, поэтому они остаются тестируемыми.
Аспекты, которые я хотел бы скрыть за интерфейсом, это взаимодействие с DataContext, например, с использованием классов в стиле репозитория:
public interface IPhoneRepository
{
IEnumerable<Phone> GetPhonesForUser(User user);
}
public class L2SPhoneRepository : IPhoneRepository
{
private readonly MyDataContext context;
public L2SPhoneRepository(MyDataContext context)
{
this.context = context;
}
public IEnumerable<Phone> GetPhonesForUser(User user)
{
return context.Phones.Where(p => p.User == user);
}
}
Я склонен считать, что связанные с Linq2Sql вещи являются деталями реализации кода доступа к данным и, как и реальная структура базы данных, не обязательно должны подвергаться воздействию других частей системы.
Если ваш API будет использоваться другими людьми, он должен быть сплоченным и простым в использовании и не загроможденным вещами, о которых потребитель не должен знать. Если я имею дело с пользователями и их телефонами, я действительно не хочу знать о DataContexts или (тьфу) DataSets.
Кроме того, сохраняя большую часть своего кода в неведении о L2S и базе данных, вам будет проще проводить тестирование, вносить изменения в схему (о, теперь в таблице User необходимо вести историю каждого внесенного изменения) или даже полностью менять ORM.,
Вы должны добавить свойство Phones в IUser и сделать его обнуляемым, поэтому для пользователя, у которого нет Phone, оно будет нулевым.
Поскольку вы не хотите, чтобы потребители API писали запросы, вам следует реализовать такие функции, как GetUser() и т. Д.
Вот хороший список статей abt n-уровневого приложения в Asp.net
Ваш интерфейс должен моделировать, как вы хотели бы использовать объекты. Поскольку вы пытаетесь абстрагироваться, потребителю не нужно запрашивать БД. Делаете ли вы это свойство или отдельный вызов функции (например, GetPhones()), полностью зависит от вас. Поскольку вы полностью упаковываете вещи, вам придется сделать выбор, насколько глубоко / лениво вы хотите загружать свои объекты.