Хранилище данных - бизнес-объекты?

Я читаю книгу «Социальные сети ASP.NET 3.5 — Эндрю Симер» и запутался, когда он использует репозитории для доступа к данным.

Вот идея его кода:

public interface IAccountRepository
{
  Account GetAcountByID(int acId);
  void SaveAccount(Account account);
  List<Account> GetAllAccounts();      
}

public class AccountRepositoryLINQ : IAccountRepository
{
  Account GetAcountByID(int acId){
    ..... LINQ query ..... 
    ...... return.....
  }
  void SaveAccount(Account account){
    ..... LINQ ..... 
  }
  List<Account> GetAllAccounts(){
    ..... LINQ query ..... 
    ...... return.....
  }
}

Класс «Учетная запись» создается автоматически в «Классы LINQ to SQL».

Некоторые проблемы, которые я вижу:

Я кодирую свой бизнес-уровень, графический интерфейс и т. д., а позже со временем таблица Accounts в базе данных изменяется (например, изменение имени одного столбца), затем мне нужно перестроить " LINQ to SQL Classes», и все мои слои кода должны быть перекодированы, потому что мой объект «Учетная запись» изменился.

Если мне нужны другие репозитории (MySQL, Oracle, XML и другие), какой класс "Учетная запись" я буду использовать?

Что делать?

  • Разве я не должен использовать собственный класс Account? Это будет использоваться во всех слоях приложения.
  • How do the mapping from LINQ to my custom Account class?
    • Using simple "myClass.Name = linqClass.Name;" ???
      • Isn't this consuming machine resources if I need to "map" all the classes?
      • Нет самого простого/легкого способа сделать это?
      • Это правильный подход? Есть ли другие способы?

person Dryadwoods    schedule 02.09.2009    source источник


Ответы (3)


У меня самого отношения любви и ненависти к классам LINQ to SQL, но я подумал, что буду играть в адвоката дьявола :-), во-первых, обращая внимание на то, что вы сделали: -

1º Я кодирую свой бизнес-уровень, графический интерфейс и т. д., а позже таблица Accounts в базе данных изменяется (например, изменение имени одного столбца), затем мне нужно перестроить «LINQ to SQL Classes» и все мои слои кода необходимо будет перекодировать, потому что мой объект «Учетная запись» изменился.

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

Даже если вы использовали POCO для сохранения, например, с NHibernate, вам все равно нужно изменить сопоставление, поэтому я не вижу в этом проблемы.

2º Если мне нужно иметь другие репозитории (MySQL, Oracle, XML и другие), какой класс «Учетная запись» я буду использовать?

Лично я бы назвал YAGNI в этом вопросе, если вы действительно ожидаете, что вам понадобится поддержка нескольких баз данных, LINQ to SQL может быть не лучшим решением для начала в любом случае (просто чтобы ваша инфраструктура была согласованной во всем приложении), такие инструменты, как NHibernate, имеют гораздо лучшую поддержку для таких ситуаций.

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

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

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

 IAccount GetById(int accountId);

Затем вы дадите себе свободу выбора реализации (т. е. реализована ли она классом LINQ to SQL или проекцией/отображением), и если вы выберете собственный класс в будущем, это будет простой случай перемещения реализацию этого класса и изменение реализации репозитория.

В конце концов, все зависит от приложения, если вы думаете, что оно в конечном итоге превратится в огромное приложение с чрезвычайно сложной бизнес-логикой, я бы выбрал слой сегрегированного домена, который, по крайней мере, пытается быть неосведомленным о постоянстве. Если, однако, это не так, то выбор шаблона репозитория — это просто средство для достижения хорошей тестируемости и простой абстракции над вашим доступом к данным. Я не понимаю, почему явная ссылка на классы LINQ to SQL и их использование в качестве простого уровня предметной области — это такая большая проблема.

person John Foster    schedule 02.09.2009

Хороший инстинкт..

Мое предложение состоит в том, чтобы абстрагироваться от объектов LinqToSQL и создать набор объектов бизнес-домена. Затем репозиторий может запросить необходимые данные и сопоставить их с объектами домена, которые использует ваше приложение, и вернуть их. Теперь ваш уровень доступа к данным отделен от вашего приложения, и теперь вы можете делать все, что перечислили.

Сопоставление может быть болезненным, поэтому для этого воспользуйтесь такими инструментами, как Automapper.

person jlembke    schedule 02.09.2009

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

person Brandon Grossutti    schedule 02.09.2009