Изменения сущности n-слоя C#, не отраженные в DTO после вставки
Извините за название, я не смог найти подходящее описание.
У меня есть четыре слоя:
- Основной уровень: содержит DTO, интерфейсы для сервисов и репозитории.
- Бизнес-уровень: содержит "сервисы", которые обрабатывают бизнес-логику.
- Уровень доступа к данным: Содержит репозитории, которые обрабатывают доступ к базе данных и преобразование объектов в DTO.
- Уровень представления: пользовательский интерфейс
Я столкнулся с проблемой, которую я не знаю, как решить лучше всего. Я асинхронно добавляю сущность в базу данных, вот так:
// The AdministrationRate has an ID property, Entity Framework does treat the property as an Identity and does increment it.
var adminRate = new AdministrationRate() {FosterChildID = fosterChild.ID};
await adminRateService.AddAdministrationRate(adminRate);
AdministrationRateService:
public async Task AddAdministrationRate(AdministrationRate administrationRate) => await repo.AddAdministrationRate(administrationRate);
AdministrationRateRepository:
//I use a generic repository to avoid code repition.
//Notice the DTO to entity conversion. ID is not set in the conversion.
public async Task AddAdministrationRate(AdministrationRate administrationRate) => await Add(administrationRate.ToEntity());
Repository:
public async Task Add(TEntity entity)
{
using (var db = new DatabaseContext())
{
db.Entry(entity).State = EntityState.Added;
await db.SaveChangesAsync();
}
}
И это работает, проблема в том, что после добавления вновь сгенерированный идентификатор сущности не был отражен в DTO (DTO.ID = 0).
Я не могу вернуть обновленную сущность, потому что это потребовало бы от меня преобразования сущности в DTO на моем уровне представления, чтобы она оставалась полностью асинхронной.
Я также не могу вернуть только идентификатор из-за общего хранилища.
Я действительно не хочу избавляться от универсального репозитория, поскольку он довольно полезен, но я не могу найти другого способа сделать это безопасно без изменения базы данных (что я не могу сделать).
Итак, что мне делать?
2 ответа
Ответ: Я нашел два решения этой проблемы, последнее из которых я и выбрал.
Решение 1:
Я понял, что мог бы заставить метод Add возвращать идентификатор сущности, пометив метод Add общего виртуального репозитория, затем переопределив его в одном из конкретных репозиториев и, наконец, отловить результат из вызывающего кода. Это, конечно, будет означать больше кода, но также и то, что я не буду конвертировать из сущностей в DTO в неправильном слое (не то чтобы это был вариант).
Решение 2:
Видимо await
Ключевое слово возвращает тип результата задачи асинхронно, а не блокирует его как result
Таким образом, я смог преобразовать и вернуть DTO из моего хранилища:
AdministrationRateRepository:
public async Task<AdministrationRate> AddAdministrationRate(AdministrationRate administrationRate) => (await Add(administrationRate.ToEntity())).ToModel();
Я хотел бы, чтобы кто-то мог прокомментировать, нужно ли мне ToEntity()
а также ToModel()
методы асинхронно, и как это будет сделано.
РЕДАКТИРОВАТЬ: О, не заметил, кто-то опубликовал. Я посмотрю ваши предложения Akos, спасибо.
Вот пара идей, которые я бы попробовал. Не уверен, что какой-либо из них удовлетворяет вашим потребностям, но может помочь вам начать (или начать обсуждение хотя бы:)):
1; Введите интерфейс для ваших DTO, как IDto
, Затем вы можете изменить общий репозиторий для возврата Task<IDto>
вместо задачи. Преобразовать сущность в конкретный Dto внутри Add
метод, вернуться через IDto
ссылку, а затем преобразовать его обратно в сервис.
2; Если у вас есть общий репозиторий, как IRepository<TEntity>
, или же Repository<TEntity>
, тогда вы можете попробовать ввести другой параметр в общий репозиторий и сделать его IRepository<TEntity,TDto>
, Таким образом, вы можете сохранить общий характер вашей архитектуры, но и вернуть Task<Dto>
от Add
метод.
3; Вы можете пойти еще дальше: создать IDto<TEntity>
интерфейс. И тогда вы можете иметь User
сущность и UserDto:IDto<User>
, Затем вы можете изменить тип возвращаемого значения Add
метод для Task<IDto<TEntity>>
, Или, опять же, используйте двухпараметрический репозиторий IRepository<TEntity,TDto>
и добавить ограничения, так что TDto
должен реализовать IDto<TEntity>
,