【问题标题】:Problem with getting inserted Id from database从数据库中获取插入 ID 的问题
【发布时间】:2019-09-14 02:21:32
【问题描述】:

我正在尝试通过实体框架从数据库中获取最后插入的 ID,但是我的问题在某种程度上是独一无二的,我无法找到任何解决方案,但要重写我的整个基础架构和业务层,所以我所有的 ID 都是 Guid ,我可以手动创建,或者在提交后通过另一个数据库调用获取最后一条记录。

这就是问题所在。我有一个三层架构,我在其中使用 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;
}

有什么优雅的解决方案吗?就像我说的,我唯一的想法是在提交后将所有 Id 切换为 Guid 或第二次调用 Id,我认为这不是很好的解决方案,因为当我想在一个事务中连接两个或多个表时,这是不可能的。

【问题讨论】:

  • 我认为应该有一种方法可以让您的数据库处理 GUID 创建。
  • Guid 创建不是问题,您可以让 Db 自动创建它,但在这种情况下,手动创建它会更有效,这样您就可以知道您要插入的 Id 而无需提交.但这是我的后备解决方案,我只想知道是否有办法使用 Integer Id 来做到这一点。
  • 如果你对存储过程没问题,那么你可以编写一些原始 sql 来使用输出子句返回插入的 id

标签: c# entity-framework asp.net-core .net-core ef-core-2.2


【解决方案1】:

该问题的 EF Core 解决方案很简单 - 在调用 SaveChanges[Async] 之后 可以使用实体实例的自动生成 PK。例如

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&lt;int&gt;,例如

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 key generation strategy,但前提是 database provider 支持它。我可以肯定地说,Microsoft.EntityFrameworkCore.SqlServerNpgsql.EntityFrameworkCore.PostgreSQL 分别支持 ForSqlServerUseSequenceHiLoForNpgsqlUseSequenceHiLo fluent API。

【讨论】:

  • 谢谢,这很有帮助,但仍有一个问题。当我在一个事务中插入多个需要相互引用的实体时,此解决方案仍然不会提供我需要添加的 Id。我知道 EF 有这个功能,但我这样做的原因是我可以通过更改最少的代码来交换 ORM。
  • 大声笑,改变 ORM 绝非易事。无论如何,EF 通过导航属性而不是 Ids 链接实体来解决 Ids 问题。但是我相信它允许您在一个上下文事务中的另一个实体中使用实体的临时 ID 作为 FK。 SaveChanges 相应地更新它们。
猜你喜欢
  • 1970-01-01
  • 2023-03-24
  • 2010-10-14
  • 1970-01-01
  • 2018-03-05
  • 1970-01-01
  • 2010-12-07
  • 1970-01-01
相关资源
最近更新 更多