Добрый день! Помогите, пожалуйста, разобраться с трехуровневой архитектурой и передачей объектов с уровня на уровень.
В приложении используется трехуровневая архитектура:
DAL (Data Access Layer) содержит:- классы Entity (сущности БД)
- класс контекста БД (Entity Framework 6)
- класс GenericRepository
public interface IGenericRepository<TEntity> : IDisposable where TEntity : class
{
IQueryable<TEntity> GetAll();
TEntity Find(object id);
void Insert(TEntity item);
void Update(TEntity item);
void Delete(object id);
void Dispose(bool disposing);
}
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
//...
}
- класс UnitOfWork
public interface IUnitOfWork : IDisposable
{
GenericRepository<T> Repository<T>() where T : class;
void Save();
void Dispose(bool disposing);
}
public class UnitOfWork<TDbContext> : IUnitOfWork where TDbContext : DbContext, new()
{
//...
}
Для работы с базой данных используется Entity Framework 6.
BLL (Business Logic Layer) содержит:- классы DTO
- классы сервисов
UI (Presentation layer) содержит:- Проект на ASP.NET MVC в котором определены ViewModels
Каждый из слоев это отдельный проект, DAL и BLL - Class Library проекты, а UI - ASP.NET MVC 4.
Вопрос заключается в следующем:
Сейчас сделано так, что GenericRepository методом GetAll возвращает IQueryable выборку всей таблицы указанной сущности TEntity, а уже в сервисе к этой выборке применяются более сложные условия, например:
public class BookService : IBookService
{
private UnitOfWork<MyContext> Db { get; set; }
public BookService()
{
Db = new UnitOfWork<MyContext>();
}
public List<BookDTO> Exmaple()
{
Mapper.CreateMap<Book, BookDTO>();
return Mapper.Map<IEnumerable<Book>, List<BookDTO>>(b.Repository<Books>().GetAll().Where(b => b.BookAccepted == true && b.ParentBookId == null).ToList());
}
}
Т.е. получается, что реальная выборка и намного более сложные запросы (например с тремя join таблицами) делаются в сервисе, но из-за этого приходится подключать Entity FrameWork и в проекте с BLL уровнем.
Насколько это правильно?
Может лучше сделать отдельный репозиторий и в нем сделать метод (в данном примере List GetAcceptedBooks()). Но в таком случае возникает следующая проблема:
Например нужно построить отчет, который можно получить из базы данных путем присоединения нескольких таблиц, что-то вроде:
SELECT b.BookName, b.BookDate, SUM(bp.BillPrice) as BookSum, p.PaidSum, np.NotPaidSum
FROM ... as b
LEFT JOIN ... as bp on ...
LEFT JOIN
(
SELECT BookId, SUM(BookId) as PaidSum
FROM ...
GROUP BY BookId
) as p on p.BookId=b.BookId
....
т.е запрос возвращает не сущность БД, а новый объект. Тогда на уровне BLL создается объект DTO, например BookReportDTO, который соответствует результату такой выборки. Но если такая выборка находится в репозитории, получается метод репозитория должен возвращать List и уровень DAL будет связан с уровнем BLL.
Будет ли это правильным?
Получается общий вопрос можно определить так: Как организовать передачу сложных объектов (НЕ СУЩНОСТЕЙ) с уровня DAL на уровень BLL? Или на уровне DAL в репозитории оставить только CRUD запросы, а уже в сервисах уровня BLL делать сложные выборки и там создавать коллекции DTO объектов?
Заранее благодарю за любую помощь!