2008-09-27 3 views
8

Я изначально разработал свою систему, следуя примеру архитектуры s # outlined in this codeproject article (К сожалению, я не использую NHibernate). Основная идея заключается в том, что для каждого объекта домена, который должен был бы связываться с уровнем сохранения, у вас будет соответствующий объект доступа к данным в другой библиотеке. Каждый объект доступа к данным реализует интерфейс, и когда объект домена нуждается в доступе к методу доступа к данным, он всегда кодирует интерфейс и никогда не относится к самим DAO.Как структурировать уровень доступа к данным?

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

Интересно, что многие из этих DAO (и их соответствующих интерфейсов) являются очень простыми существами - наиболее распространенным является только один метод GetById(). Я в конечном итоге с целой кучей объектов, таких как

public interface ICustomerDao { 
    Customer GetById(int id); 
} 

public interface IProductDao { 
    Product GetById(int id); 
} 
public interface IAutomaticWeaselDao { 
    AutomaticWeasel GetById(int id); 
} 

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

public interface SimpleObjectRepository { 
     Customer GetCustomerById(int id); 
     Product GetProductById(int id); 
     AutomaticWeasel GetAutomaticWeaselById(int id); 
     Transaction GetTransactioinById(int id); 
} 
public interface TransactionDao { 
    Transaction[] GetAllCurrentlyOngoingTransactionsInitiatedByASweatyGuyNamedCarl(); 
} 

Есть ли у кого-нибудь опыт работы с подобной архитектурой? В целом я очень доволен настройкой, поскольку теперь моя единственная забота - управлять всеми этими маленькими файлами. Мне все еще интересно, какие существуют другие подходы к структурированию уровня доступа к данным.

ответ

3

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

Таким образом, мой подход должен иметь репозиторий для каждого необходимого ему агрегата, такого как CustomerRepository. Это будет иметь метод Add (save) и, если это подходит для этого агрегата, метод Remove (удалить). Он также будет использовать любые другие настраиваемые методы, включая запросы (GetActive), и, возможно, некоторые из этих запросов могут принять спецификации.

Это звучит очень много, но помимо пользовательских запросов большая часть кода, по крайней мере, если вы используете современную ORM, очень проста в реализации, поэтому я использую наследование (ReadWriteRepositoryBase, где T: IAggregateRoot) и/или состав (вызов класса RepositoryHelper). Базовый класс может иметь методы, которые применяются во всех случаях, например GetById.

Надеюсь, это поможет.

1

Я также использую repository pattern для моего DAO, и я вполне доволен этим. Да, в итоге вы получаете немало небольших классов, но это очень удобно. Это немного более эффективно, если вы используете интерфейс IQueriable (LINQ.) Вы также можете использовать generics (что-то вроде T GetById<T>(int id)), если у вас довольно согласованная структура базы данных.

2

Я работаю на PHP, но у меня есть что-то подобное для моего уровня доступа к данным. Я реализовал интерфейс, который выглядит примерно так:

class DataAccessObject implements DataAccessObject 
{ 
    public function __construct($dao_id = null) // So you can construct an empty object 
    { 
     // Some Code that get the values from the database and assigns them as properties 
    } 
    public static function get(array $filters = array(), array $order = array(), array $limit = array()) {}; // Code to implement function 
    public function insert() {}; // Code to implement function 
    public function update() {}; // Code to implement function 
    public function delete() {}; // Code to implement function   
} 

я в настоящее время строит каждый из классов объектов доступа к данным вручную:

interface DataAccessObject 
{ 
public static function get(array $filters = array(), array $order = array(), array $limit = array()); 
public function insert(); 
public function update(); 
public function delete(); 
} 

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

Однако вы также можете использовать метаданные SQL (предполагая, что у вас есть довольно прочная база данных, которая использует ограничения внешнего ключа и т. П.) Для создания этих объектов доступа к данным. Тогда, теоретически, вы можете использовать один родительский класс DataAccessObject для создания свойств и методов класса и даже автоматического создания связей с другими таблицами в базе данных. Это более или менее выполнит то же самое, что вы описываете, потому что тогда вы можете расширить класс DataAccessObject, чтобы предоставить настраиваемые методы и свойства для ситуаций, требующих некоторого количества созданного вручную кода.

В качестве побочной цели для разработки .NET вы рассмотрели инфраструктуру, которая обрабатывает базовую структуру уровня доступа к данным для вас, например Subsonic? Если нет, я бы рекомендовал изучить именно такую ​​структуру: http://subsonicproject.com/.

Или для разработки PHP, рамки, такие как Zend Framework обеспечит аналогичную функциональность: http://framework.zend.com

+0

никогда не слышал о дозвуковой прежде, спасибо за подсказку. Выглядит очень интересно – 2008-09-28 18:37:19

2

Джордж, я знаю точно, как Вы чувствуете. Архитектура Билли имеет смысл для меня, но необходимость создания контейнера, файлы Imapper и mapper болезненны. Затем, если вы используете NHibernate, вызывающий коррозию файл .hbm и обычно несколько тестовых сценариев для проверки работы каждого.

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

public class BaseDAO<T> : IDAO<T> 
{ 
    public T Save(T entity) 
    { 
     //etc...... 
    } 
} 
public class YourDAO : BaseDAO<YourEntity> 
{ 
} 

Я думаю, что без NHibernate вы бы с помощью отражения или какой-либо другой machanism к определить, что SQL/SPROC для вызова?

В то же время, моя мысль об этом будет заключаться в том, что DAO необходимо выполнить только основные операции CRUD, определенные в базовом классе, тогда не должно быть необходимости писать настраиваемые карты и интерфейсы. Единственный способ, которым я могу придумать, - это использовать Reflection.Emit для динамического создания DAO на лету.

0

Основной обратный подход к второму подходу заключается в модульном тестировании - издевательства над крупными фабричными методами, такими как ваш SimpleObjectRepository, требует больше работы, чем издевательствовать только ICustomerDao. Но мой проект идет со вторым подходом к высоко связанным объектам (где большинство будет использоваться в любых модульных тестах), поскольку оно облегчает умственную нагрузку и делает его более удобным.

Я бы выяснил, что делает вашу систему более удобной и удобной для понимания и делает это.

Смежные вопросы