Проблема с получением вставленного идентификатора из базы данных - PullRequest
3 голосов
/ 24 апреля 2019

Я пытаюсь получить последний вставленный идентификатор из базы данных через Entity Framework, однако моя проблема почему-то уникальна, и я не могу найти никакого решения, кроме как переписать всю свою инфраструктуру и бизнес-уровень, поэтому все мои идентификаторы являются путеводителями, который я могу создать вручную или получить последнюю запись с другим вызовом базы данных после коммита.

Вот проблема.У меня трехуровневая архитектура, в которой я использую UoW, репозиторий, сервисы и фасады.Я покажу свой код сверху вниз, чтобы вы могли понять.

Вот мой фасад, где uow.Commit звонит SaveChanges()

public async Task<int> RegisterUserAsync(UserCreateDto user)
{
        using (var uow = UnitOfWorkProvider.Create())
        {
            var id = _userService.Create(user);
            await uow.Commit();
            return id;
        }
}

Как видите, яотправляя только мой DTO в службу, где я обрабатываю, как это, также я отображаю внутри службы

public virtual int Create(TCreateDto entityDto)
{
        var entity = Mapper.Map<TEntity>(entityDto);
        Repository.Create(entity);
        return entity.Id;
}

и, наконец, мой репозиторий выглядит так

public TKey Create(TEntity entity)
{
        Context.Set<TEntity>().Add(entity);
        return entity.Id;
}

Есть ли некоторые элегантныерешение этого?Как я уже говорил, моя единственная идея - переключить все идентификаторы на Guid или второй вызов Id после фиксации, что я считаю не очень хорошим решением, потому что, когда я хочу соединить две или более таблиц в одной транзакции, это будет невозможно.

1 Ответ

5 голосов
/ 24 апреля 2019

EF Основное решение проблемы простое - автоматически сгенерированный PK экземпляра сущности доступен после вызова SaveChanges[Async].например,

var entity = Mapper.Map<TEntity>(entityDto);
Context.Add(entity);
// Here entity.Id contains auto-generated temporary value
// Other stuff...
Context.SaveChanges();
// Here entity.Id contains actual auto-generated value from the db

Таким образом, проблема заключается не только в дизайне вашей инфраструктуры - все эти (ненужные) UoW, хранилище, сервисы и фасады просто скрывают эту функциональность.

Единственное относительно простое иэлегантное решение, которое я вижу в вашей архитектуре, заключается в изменении типа возвращаемого сервиса с int на Func<int>, например,

public virtual Func<int> Create(TCreateDto entityDto)
{
    var entity = Mapper.Map<TEntity>(entityDto);
    Repository.Create(entity);
    return () => entity.Id; // <--
}

Тогда на вашем фасаде вы можете использовать

public async Task<int> RegisterUserAsync(UserCreateDto user)
{
    using (var uow = UnitOfWorkProvider.Create())
    {
        var id = _userService.Create(user);
        await uow.Commit();
        return id(); // <-- the actual id!
    }
}

Редактировать:

На самом деле EF Core предоставляет еще одну опцию, которая позволит вам сохранить ваш текущий дизайн без изменений - стратегия генерации ключей HiLo , но только если поставщик базы данных поддерживает его.Я могу с уверенностью сказать, что Microsoft.EntityFrameworkCore.SqlServer и Npgsql.EntityFrameworkCore.PostgreSQL поддерживают его соответственно с ForSqlServerUseSequenceHiLo и ForNpgsqlUseSequenceHiLo текущими API.

...