В своих приложениях я использую подход разделение функционала на слои, слои я стараюсь группировать на основании функциональности
Data Access Object
Data Access Layer
Business Logic Layer
GUI
Для работы с бд я использую entity-framework. Довольно часто я стал ловить себя на мысли что я не понимаю/не уверен на каком из слоев должна быть реализована та или иная функциональность
Например: необходимо получить список объектов из бд, пусть класс будет называться Request, тогда я делаю так:
В DAL у меня есть generic репозиторий() c реализацией CRUD и торчащим наружу свойством protected virtual IQueryable
В BLL я обращаюсь к свойству Entities вытягиваю из бд необходимые мне данные, материализую(ToList()Single()), преобразую в DTO объекты которые отдаю в GUI
В целом меня такой подход устраивал всем, базовые методы(CRUD) реализованы в одном классе реализующим generic репозиторий, методы для работы с конкретными сущностями реализованы в слое BLL
Но тут наступил переломный момент: мне понадобилось использовать хранимые процедуры/функции
Для поддержания чистоты приложения доступ к хранимкам хочу(мне так кажется правильней) сделать в слое DAL я это представляю как то так :
Сделать IRequestRepository в который в качестве зависимости передать generic репозиторий плюс реализовать необходимые методы/функции, например такие как обращение и получения результата хранимой функции, так же мне будет необходимо выставить наружу в generic репозитории DbContext что бы можно было обращаться к хранимкам(_context.Database.SqlQuery
как альтернатива отказаться от generic репозитория и для каждого необходимого класса из DAO реализовать класс репозитория, но в этом случае в каждом классе будет дублирование CRUD методов, что мне кажется не правильным.
Пример реализации:
public interface IRepository
T GetById(object id);
void Insert(T entity);
void Insert(IEnumerable
public interface IRequestRepository
{
Request GetById(object id);
void Insert(Request request);
void Insert(IEnumerable
public class RequestRepository: IRequestRepository
{
private readonly IRepository
public RequestRepository(IRepository
#region Методы обертки над методами из IRepository
Request GetById(object id) {...}
void Insert(Request request) {...}
void Insert(IEnumerable
#region Методы обертки над хранимыми функциями/процедурами
IEnumerable
//Прочие методы
}
Как все таки лучше/правильней поступить в описанном мной случае?
UPD:
исходя из ответа @PavelMayorov, если я правильно понял структура классов у меня вырисовывается следующим образом
public interface IRequestRepository
{
#region CRUD методы
Request GetById(object id);
void Insert(Request request);
void Insert(IEnumerable
public interface IRequestHistoryRepository
{
#region CRUD методы
#endregion
}
public class RequestRepository: IRequestRepository
{
private readonly DbContext _context;
public RequestRepository(DbContext context)
{
this._context=context;
}
// Реализация необходимых методов
// для работы с "сущностью"
}
public class RequestHistoryRepository: IRequestHistoryRepository
{
private readonly DbContext _context;
public RequestHistoryRepository(DbContext context)
{
this._context=context;
}
// Реализация необходимых методов
// для работы с "сущностью"
}
вот только в этом случае будет дублирование в каждом таком репозитории кода CRUD
try
{
if (request == null)
throw new ArgumentNullException("entity");
//Создание/Чтение/Редактирование/Удаление
}
catch (DbEntityValidationException dbEx)
{
var msg = string.Empty;
foreach (var validationErrors in dbEx.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
var fail = new Exception(msg, dbEx);
//Debug.WriteLine(fail.Message, fail);
throw fail;
}
Ответ
Репозиторий со свойством IQueryable
Вообще говоря, в простых программах слоем DAL можно считать саму библиотеку EF; делать поверх новый слой - странное занятие. Если ваша программа достаточно простая - то просто выкиньте из нее все репозитории и увидите как все стало проще :)
Основная проблема слоев DAL в типичных программах - потеря инкапсуляции, схема хранения напрямую связана с внешним интерфейсом из-за использования типов модели хранения в интерфейсах.
Если вам действительно нужен отдельный слой DAL - предлагаю вам выкинуть из его интерфейсов все упоминания моделей EF. Хранение данных должно быть полностью скрыто в слое DAL, никаких классов-сущностей или IQueryable<> наружу торчать не должно. Код уровня бизнес-логики не должен знать, простой ли запрос идет к базе - или же вызывается хранимая процедура.
Что же до повторяющегося кода - есть стандартные способы борьбы с ним: методы-хелперы, базовые классы, AOP.
Комментариев нет:
Отправить комментарий