【问题标题】:Why does this throw a PK duplicate error?为什么这会引发 PK 重复错误?
【发布时间】:2019-05-08 07:57:40
【问题描述】:

这是我的测试用例,我希望它是不言自明的。

    [Fact]
    public async Task ShouldAllowEntityUpdate()
    {

        var _tenantRepo = LocalIocManager.Resolve<IRepository<Tenant>>();

        Tenant tenant = _tenantRepo.Insert(new Tenant("Tname", "name"));

        var _userRepo = LocalIocManager.Resolve<IRepository<User,long>>();

        _userRepo.Insert(new User()
        {
            Tenant = tenant,
            Name = "jojo"
        });

    }

这会引发错误,因为它会在_userRepo.Insert 期间尝试(再次)创建新租户。是不是应该被 EF 跟踪,从而知道它是一个现有的实体?

这里有一份快速回购的副本: https://github.com/Worthy7/AspAbpSpa/commit/d40f238480934a472a122d6ca6f5cda7ed8e21cd

Test Name:  AspAbpSPAMay.Tests.PkDupBug.ShouldAllowEntityUpdate
Test FullName:  AspAbpSPAMay.Tests.PkDupBug.ShouldAllowEntityUpdate
Test Source:    C:\Users\Ian\Source\Repos\AspAbpSPAMay\4.6.0\test\AspAbpSPAMay.Tests\PkDupBug.cs : line 13
Test Outcome:   Failed
Test Duration:  0:00:04.126

Result StackTrace:  
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at Microsoft.EntityFrameworkCore.InMemory.Storage.Internal.InMemoryTable`1.Create(IUpdateEntry entry)
   at Microsoft.EntityFrameworkCore.InMemory.Storage.Internal.InMemoryStore.ExecuteTransaction(IReadOnlyList`1 entries, IDiagnosticsLogger`1 updateLogger)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList`1 entriesToSave)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Abp.EntityFrameworkCore.AbpDbContext.SaveChanges() in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\AbpDbContext.cs:line 208
   at Abp.Zero.EntityFrameworkCore.AbpZeroCommonDbContext`3.SaveChanges() in D:\Github\aspnetboilerplate\src\Abp.ZeroCore.EntityFrameworkCore\Zero\EntityFrameworkCore\AbpZeroCommonDbContext.cs:line 159
   at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.SaveChangesInDbContext(DbContext dbContext) in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs:line 163
   at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.SaveChanges() in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs:line 60
   at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.CompleteUow() in D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs:line 77
   at Abp.Domain.Uow.UnitOfWorkBase.Complete() in D:\Github\aspnetboilerplate\src\Abp\Domain\Uow\UnitOfWorkBase.cs:line 256
   at Abp.Domain.Uow.UnitOfWorkInterceptor.PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options) in D:\Github\aspnetboilerplate\src\Abp\Domain\Uow\UnitOfWorkInterceptor.cs:line 68
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.IRepository`2Proxy_4.InsertOrUpdate(User entity)
   at AspAbpSPAMay.Tests.PkDupBug.ShouldAllowEntityUpdate() in C:\Users\Ian\Source\Repos\AspAbpSPAMay\4.6.0\test\AspAbpSPAMay.Tests\PkDupBug.cs:line 23
--- End of stack trace from previous location where exception was thrown ---
Result Message: System.ArgumentException : An item with the same key has already been added. Key: 2

如果这是错误的方法,那么正确的方法是什么?

查看answer on this other question 似乎我的租户实体由于某种原因正在分离。是不是因为它需要在 UOW 中才能继续跟踪?

【问题讨论】:

  • 你能分享你在 SQL 中的表定义吗? (脚本表作为/创建)
  • 可能是InMemoryStore 的限制。你在实际应用中遇到过这种情况吗?
  • 是的,当然,这就是我编写测试的原因。我承认错误文本本身略有不同,但含义相同。

标签: aspnetboilerplate


【解决方案1】:

正确版本:

[Fact]
    public async Task ShouldAllowEntityUpdate()
    {
        var unitOfWorkManager = Resolve<IUnitOfWorkManager>();

        var _tenantRepo = LocalIocManager.Resolve<IRepository<Tenant>>();

        Tenant tenant = _tenantRepo.Insert(new Tenant("Tname", "name"));

//COMMIT CHANGES to GET the new tenant's Id
_unitOfWorkManager.Current.SaveChanges();

        var _userRepo = LocalIocManager.Resolve<IRepository<User,long>>();

//Use TenantId to set the tenant.
        _userRepo.Insert(new User()
        {
            TenantId = tenant.Id,
            Name = "jojo"
        });

    }

【讨论】:

  • 最后归结为 UoW 没有保存更改。因此,结束 UoW 并开始新的 UoW 看到了新的变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多