К какому слою относится Repository и как возвращать Business object?
Язык не важен. Например, у меня есть база данных с таблицей User.
В моей программе есть Data Access Layer (DAL) и Business Logic Layer (BLL).
В DAL для таблицы User у меня написан класс сущности UserEntity{username, secondname, age ...}, которая, соответственно и отражает в себе данные отдельного поля таблицы.
В своем BLL у меня есть объект User{fullname, age}, который получается путем превращения UserEntity -> User, т.е. происходит mapping.
Также у меня есть UserRepository, который инкапсулирует работу с хранилищем и возвращает данные. Вот здесь у меня и возникли вопросы:
1) Что должен возвращать UserRepository : UserEntity или User?
2) В каком слое должен находиться UserRepository DAL или BLL
Если по логике, то DLL вообще не должен знать про BLL, тем более про его объекты. Но выходить, что если я хочу, чтобы
репозиторий возвращал User, то получается DLL подвязан на BLL. То есть, если репозиторий находится в DAL, то он никак не должен возвращать объекты BLL. Но во многих статьях я видел, что наоборот, пишут - repository возвращает Business objects.
Привет! Многое зависит от деталей и количества абстракций. Попытаюсь ответить как это должно выглядеть в самом общем случае. UserRepository использует напрямую доступ к базе данных (это может быть raw sql, какая-то ORM, неважно). Поэтому логично, чтобы он находился в Data Access Layer. Он поэтому так и называется, потому что на практике их может быть несколько: SqlDataAccessLayer, MongoDbDataAccessLayer и т.д. Также если мы говорим про ООП, то интерфейс IUserRepository должен хранится именно там, где планируется его использование. В нашем случае это BLL, он же Domain Layer. Не всегда удаётся придерживаться этого правила с интерфейсом, но к этому нужно стремиться.
По поводу того, что должен возвращать UserRepository: на самом деле без разницы. Смотря от ситуации мы можем либо возвращать просто контейнер c необходимыми данными (DTO), либо полноценного User'a. Если говорить о зависимостях, то главное понимать, что в общем случае наш Domain Layer не должен иметь зависимостей от каких-то других слоёв. А вот остальные части нашего проекта (например, DAL) могут использовать Domain Layer.
Привет! Если будем возвращать User из UserRepository, то получается, что DAL знает о BLL. В этом то и вопрос) В будущем я не смогу сборку DAL дать моему другу, например. Придется со всеми зависимостями.
DAL может знать о BLL, главное не наоборот. Сборку DAL не нужно давать друзьям :) DAL без бизнес логики не имеет смысла, потому что его цель - связывать бизнес логику с базой данных.
как правило Repository - уровень инфраструктуры а не домена, с доменом они связанны интерфейсами.
например доменная сущность (по сути это BLL):
Domains/User/User
Domains/UserCollection
Domains/User/RepositoryInterface (возвращает User, UserCollection)
Инфраструктура:
Infrastructure/User/Repository (реализует RepositoryInterface, работает с бд, использует DAL, mapping)
Есть проект Domain в котором описаны общие интерфейсы для BLL и View(REST, SOAP, CLI, Desktop и т.д.). Тут есть некий интерфейс IUserService, который работает с User.
Есть проект со всей бизнес логикой, который реализует IUserService в UserService. Этот UserService ходит в DAL, откуда получает UserEntity и преобразовавает её в User. Кроме этого здесь происходят валиадации, отправка нотификаций, т.е. все что нужно бизнес логике. Отдельно есть проект DAL, который уже ходит в базу и возвращает UserEntity через UserRepository.
View при этом знает только o существования Domain проекта, а все реализации пробрасываются через IoC.
Я описал абстрактный пример, он может варироваться от платформы и размера приложения
class User {Id, Name, Age}
class UserRepository
{
User GetUserById(long Id)
{
string[] data = {select from Users where id = Id}
return new User() {Id = Id, Name = data[0], Age = data[1] };
}
void PutUser(User)
{
{insert into Users}
}
}
Зачем вам UserEntity? Если у вас доменный объект User - везде его и передавайте, и Repo олжен его же вертать при чтении из БД и его же принимать чтоб сохранять в БД.
Если вопрос в EntityFramework (и иже с ними ORM) с обязательным отнаследованием от базового Entity класса - ну сделайте маппинг опять же внутри UserRepo и не отдавайте вообще никогда вовне UserEntity, всмысле как private class например чисто для namespace / пакета