Июнь 4, 2008
Linq to SQL и DDD
В данной статье описывается создание инфраструктуры, позволяющей использовать технологию Linq to SQL и методику DDD. Сразу же даю ссылку на исходники, для тех кому надо по быстрому получить рабочее решение.
Замечательная книга Джимми Нильсена Applying Domain-Driven Design and Patterns: With Examples in C# and .NET хороший материал о разработке комплексных проектов через тестирование. Книга была написана еще до выхода технологии LINQ. Майкрософт сделал многое для того, чтоб ORM стал простым в .NET разработке.
Некоторые принципы DDD: Обьекты – POCO – они не знают про ORM, являясь наследниками Object. Репозитории – классы отвечающие за извлечение и сохранение обьектов. Архитектура, базируется на модели.
В блоге Скота Гу, много материала по LINQ, но там ни слова про DDD.
Класс DataContext, идущий рядом с паттерном UnitOfWork, имеет серьезный недостаток – не реализует интерфейса. Что сильно затрудняет юнит тестинг (нельзя подделать реализацию с помощью Mock objects) Здорово, что проблема уже решена: Using Mock Objects When Testing LINQ Code - вполне рабочее решение, но мне ближе другая реализация. Trying Out Persistence Ignorance with LINQ - эту реализацию я и взял за основу решения, использованного в моем проекте.
Способ состоит в том, чтоб сделать интерфейс UnitOfWork, который инкапсулирует в себе все взаимодействие с хранилищем. Так что, будет очень легко подставить в классы для тестирования поодельную реализацию.
Сама реализация кратко ниже:
Настоящий источник данных делегирует все родному классу DataContext.
Настоящий UnitOfWork создает PersistentDataSource и считывает маппинг классов из хмл файла, дизайнер классов я не использую и вам не советую.
Поддельная реализация IDataSource весьма проста – она все делегирует классу List
Пример
Есть таблица со странами. Для демонстрации связи с другой таблицей я указал Это означает, что в стране могут быть привязанны пользователи.
Класс страны Простой класс, практически POCO. Практически, потому что связь описывается при помощи коллекции EntitySet. Линк использует этот класс для автоматической загрузки графа обьектов.
Так выглядит ссылка в классе User на класс страны. Так в хмл
Сохраняемые в БД классы я храню в одном проекте с ифраструктурой сохраняемости. Иначе у меня не получалось корректно инициализировать UnitOfWork. Далее все как по книге Нильсена.
Репозитории
Я создал базовый код для репозитория, чтоб уменьшить дублирование
Так выглядит NUnit тест


Прикольно, но в примере для NUnit в 11 строчке наверно сравнение ua.CountryName и Ukraine.CountryName а не ua.CountryName и ua.CountryName
да, точно
public Repository():this(new UnitOfWork())
здесь наверное вместо this должно быть base
не, все правильно, репоситорий базовый класс, у него еще есть конструктор с параметром IUnitOfWork (14 строка)
ааа, невнимательно смотрел, да и такую конструкцию увидел в первый раз)