Инъекция DAO в сущности - это плохо? - PullRequest
1 голос
/ 22 октября 2008

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

Следующим шагом обычно является создание объектов сущностей, которые расширяют базовый класс DAL, поэтому у вас есть, например,

public class User : UserDAL
{
    //User specific methods
}
public class UserDAL
{
  //Bunch of user specific properties
  public User Load(int Id)
  {
    //Some low level ADO calls
  }
  private User LoadFromDataSet(DataSet ds)
  {
     //Load entity properties from DataSet 
  }    
}

Пользователь расширяет объекты UserDAL, которые имеют низкоуровневые вызовы доступа к данным, используя ADO.NET.

Отсюда вы узнаете, что эта реализация означает, что вы привязаны к уровню доступа к данным, и вы используете отдельную сущность, объект доступа к данным и интерфейс DAO для насмешки или для простой замены DAO в случае необходимости. т.е. * +1008 *

public UserDAO : IUserDAO
{
  //Data access Functions
}

С использованием обобщений и рефлексии или хорошего ORM вы можете облегчить некоторые из наиболее распространенных операций CRUD для доступа к данным, т.е.

Public UserDAO<User> : BaseDAO<User>, IUserDAO
{
  //BaseDAO deals with basic crud so more custom data access methods can go here 
}

Так что в основном это то, где я сейчас нахожусь, кроме некоторых других полезных практик, таких как использование IoC для разрешения конкретного IUserDAO, который я хочу. Но хотя я вижу преимущество этой структуры, мне также кажется, что я скучаю по старым вызовам метода User.Load (1).

Что мне было интересно, так ли плохо было бы внедрить мой IUserDAO в сущность «Пользователь» и взять ли это на себя все основные операции CRUD?

Насколько я понимаю, в качестве POCO у объекта User не было бы никаких проблем, передаваемых по проводам, и добавление таких методов, как Save (), Load () и т. Д., Не имело бы смысла в смысле объекта передачи данных.

Но с учетом этого мои сущности обычно имеют лениво загруженные коллекции, которые ничего не значат в смысле DTO. Кроме того, я считаю, что с WFP можно выбрать, какие свойства я хочу сериализовать, или, по крайней мере, я могу создать новое UserDTO, когда мне нужно будет отправить его по проводам.

Таким образом, помимо этой проблемы, каковы другие проблемы с включением моего объекта User в методы, связанные с DataAccess? Также может кто-то уточнить, называется ли то, о чем я говорю, активной моделью записи или это что-то еще?

РЕДАКТИРОВАТЬ:

Cristianlibardo отметил:

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

Был бы некоторый уровень связи, но я думал, что-то вроде следующего:

public class User
{
   IUserDAO userDAO;
   public User()
   {
         userDAO = IoCContainer.Resolve<IUserDAO>;
   }
  public User(IUserDAO userDAO)
   {
         this.userDAO = userDAO;
   }
   //DAL methods
}

Таким образом, связь должна быть минимальной, а что касается тестируемости, я не вижу в этом проблемы, поскольку я могу просто ввести фиктивный DAO в сущность.

Благодаря Брайану Хасдену, это действительно хорошие ресурсы, но я думаю, я просто хотел оправдать то, что я собирался сделать. Спасибо за предоставленное обоснование.

Ответы [ 3 ]

1 голос
/ 22 октября 2008

Да, то, что вы описываете, звучит так же, как активная запись (строка базы данных, превращенная в объект с логикой для сохранения себя из базы данных). Это эффективная техника, без сомнения.

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

1 голос
/ 22 октября 2008

Я пришел к такому же выводу. Загрузка обычно не имеет смысла в сущности, потому что, когда у вас есть экземпляр, вы либо создаете новую сущность, либо уже получили загруженную сущность. Я использую объекты с Save (создавать и обновлять) и Delete уже много лет без каких-либо проблем. При этом, как правило, полезно иметь DAO для других целей, поэтому вы не совсем объединяете DAO и сущность. Для моих сущностей большую часть времени методы Save и Delete просто вызывают методы DAO Save и Delete.

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

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

Более подробную информацию вы можете найти по адресу:

http://www.martinfowler.com/bliki/AnemicDomainModel.html http://wrschneider.blogspot.com/2005/01/avoiding-anemic-domain-models-with.html http://www.dotnetjunkies.com/WebLog/richardslade/archive/2007/03/07/209401.aspx

0 голосов
/ 23 октября 2008

Сохранение постоянства в моделях наследования классов вашего домена в значительной степени служит цели написания понятного и поддерживаемого кода.

Упорство - это ортогональная забота о реальных обязанностях вашего класса. Я заметил, что подход «наследование от DAO» произвольно делит мир на две категории классов, которые с точки зрения ответственности и поведения ничем не отличаются. На какую сторону падает класс, часто со временем меняется. Вы не хотите, чтобы это изменение влияло на API этого класса и взаимодействие с другими классами.

Пример. Предположим, что сегодня ваш класс Product использует IPriceCalculator, полученный через IoC. Завтра вы решите, что вам нужно разрешить модификацию алгоритмов для каждого продукта, поэтому ваш IPriceCalculator становится управляемым данными. Это может быть болезненным изменением, особенно если в ваших калькуляторах цен уже есть базовый класс, обеспечивающий важные функции.

Этот пример подчеркивает другое соображение: наследование от класса DAO означает, что ваш класс User только что потерял способность наследовать класс Person, который может иметь полезное поведение. (В мире .NET MarshalByRefObject - это общий базовый класс, который необходимо наследовать людям, который может вступать в конфликт с требованиями DAO на основе наследования.) При одиночном наследовании не идеальное наследование для получения функциональности, которая, вероятно, является отдельной задачей. 1007 *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...