Изменения сущности 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>,

Другие вопросы по тегам