6

我正在使用这样的内存 EF Core 数据库:

            var options = new DbContextOptionsBuilder<DmpContext>()
            .UseInMemoryDatabase("test")
            .Options;

        var context = new CustomContext(options);

我正在使用 Bogus 添加一些随机数据。

            var resources = new Faker<Resource>()
            .RuleFor(x => x.Name, x => x.Name.FullName())
            .Generate(20);

在此资源集合中,所有 id 仍然为零。

当我执行 AddRange 时,我希望生成 id:

                context.Resources.AddRange(resources);
                context.SaveChangesAsync();

但它们不是生成的。

System.AggregateException :发生一个或多个错误。(无法跟踪实体类型“资源”的实例,因为已经在跟踪具有与 {'ResourceId'} 相同键值的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

所以我想,然后让我设置它们并自己制作一个自动增量机制。那行得通。

但是,当我尝试测试我的Add方法时(这些方法插入记录)。我无法在这些方法中设置 ID,因为 ID 甚至不在界面中。我再次希望 EF 自动生成 ID,但它会尝试插入 ID 1(这已经被采用,因为我已经生成了 ID 1 直到 20)。

有谁知道如何告诉内存数据库中的 EF 核心始终自动递增它的键?

4

2 回答 2

1

在内存数据库中,EF 无法检测到实体的身份属性,我已覆盖

InMemoryIntegerValueGenerator

处理这个问题的类。下面的代码显示了如何做到这一点。

public abstract class BaseEntity
{
    public long ID { get; set; }
}

public class RoleResource : BaseEntity
{
    public long RoleID { get; set; }
    public long ResourceID { get; set; }
}

public class CASDbContext : DbContext
{
    public CASDbContext(DbContextOptions options) : base(options) { }
    public DbSet<RoleResource> RoleResources { get; set; }
}


public class CustomInMemoryIntegerValueGenerator<TEntity> 
: InMemoryIntegerValueGenerator<long> where TEntity : BaseEntity
{
    private long _current;
    public override bool GeneratesTemporaryValues => false;
    public override long Next(EntityEntry entry)
    {
        long result;
        if (entry.Properties.Any(x => x.Metadata.ValueGenerated == ValueGenerated.OnAdd))
        {
            _current = entry.Context.Set<TEntity>()
                                    .Select(x => x.ID)
                                    .DefaultIfEmpty(0)
                                    .Max(x => x);
            var res = Interlocked.Increment(ref _current);
            result = res;
        }
        else
            result = base.Next(entry);
        return result;
    }
}
public class InMemoryDbContext : CASDbContext
{
    public InMemoryDbContext(DbContextOptions options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<RoleResource>(rr =>
        {
            rr.HasKey(e => e.ID);
            rr.Property(e => e.ID)
           .HasValueGenerator<CustomInMemoryIntegerValueGenerator<RoleResource>>();
        });
    }
}

    [TestInitialize]
    public void Setup()
    {
        srvCollection.AddScoped<SeedData>();
        srvCollection.AddTransient<CASDbContext, InMemoryDbContext>();
        srvCollection.AddDbContext<InMemoryDbContext>(x => 
          x.UseInMemoryDatabase("In-Memory")).AddEntityFrameworkInMemoryDatabase();

        _serviceProvider = srvCollection.BuildServiceProvider();

    }
/* The packages version
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.2.6" />
*/
于 2020-03-10T20:37:27.060 回答
-5

您应该在实体框架设计器或代码中将标识字段标记为标识。EF 自己管理所有的身份生成机制。

检查此资源

这是您在编辑器中设置它的方式(按 f4 或右键单击身份字段上的属性):

在此处输入图像描述

于 2017-12-11T14:30:43.890 回答