Entity framework core 如何控制实体框架核心中内存中生成的键值? 背景

Entity framework core 如何控制实体框架核心中内存中生成的键值? 背景,entity-framework-core,integration-testing,in-memory-database,Entity Framework Core,Integration Testing,In Memory Database,我正在开发一个基于ASP.NET Core 2.1和EntityFrameworkCore 2.1.1的Web应用程序。除了其他类型的测试外,我还经常对Web.Api进行一些集成测试 由于测试数据相当复杂,我基于迁移数据库的一个片段生成了一个JSON文件,当内存测试开始时,测试将从这个JSON文件导入数据 问题 只读测试工作正常。但是,当我为具有标识(ValueGenerated==ValueGenerated.OnAdd)的实体插入某些内容时,它会自动获得值1(所有PK都是ints)。这是有意

我正在开发一个基于ASP.NET Core 2.1和EntityFrameworkCore 2.1.1的Web应用程序。除了其他类型的测试外,我还经常对Web.Api进行一些集成测试

由于测试数据相当复杂,我基于迁移数据库的一个片段生成了一个JSON文件,当内存测试开始时,测试将从这个JSON文件导入数据

问题 只读测试工作正常。但是,当我为具有标识(
ValueGenerated==ValueGenerated.OnAdd
)的实体插入某些内容时,它会自动获得值1(所有PK都是
int
s)。这是有意义的,因为没有指示生成器EF在幕后使用以生成这些值的任何对象根据特定值生成

但是,对于生成现有键值的插入,这显然不能正常工作。

我尝试过的事情
  • [当前工作解决方案]移动键值-反序列化所有对象后,我对所有涉及的实体执行ids shift操作(它们获得“大”值)。这可以正常工作,但容易出错(例如,某些实体具有静态ID,我必须确保所有外键/导航属性都已正确定义,而且现在速度有点慢,因为我依赖反射来正确识别需要移动的键/导航属性)

  • :

  • TestStartUp.cs
    services.AddSingleton();
    services.AddSingleton();
    
    Ids生成功能
    public const int StartValue=100000000;
    类ResettableValueGenerator:ValueGenerator
    {
    私有内部电流;
    public override bool GeneratesTemporaryValues=>false;
    公共覆盖int Next(EntityEntry)
    {
    返回联锁增量(参考电流);
    }
    public void Reset()=>_current=StartValue;
    }
    公共静态void ResetValueGenerators(CustomApiContext上下文,IValueGeneratorCache缓存,int startValue=startValue)
    {
    var allKeyProps=context.Model.GetEntityTypes()
    .Select(e=>e.FindPrimaryKey().Properties[0])
    其中(p=>p.ClrType==typeof(int));
    var keyProps=allKeyProps.Where(p=>p.ValueGenerated==ValueGenerated.OnAdd);
    foreach(keyProps中的var keyProperty)
    {
    变量生成器=(ResettableValueGenerator)cache.GetOrAdd(
    keyProperty,
    keyProperty.DeclaringEntityType,
    (p,e)=>新的ResettableValueGenerator());
    generator.Reset();
    }
    }
    
    调试时,我可以看到我的实体正在迭代,因此应用了重置

    将数据推入内存中的数据库
    private void InitializeSeeding(IServiceScope范围)
    {
    使用(范围)
    {
    var services=scope.ServiceProvider;
    尝试
    {
    var context=services.GetRequiredService();
    //这会将反序列化数据+静态数据推送到数据库中
    InitDbContext(context);
    var valueGeneratorService=services.GetRequiredService();
    重置ValueGenerators(上下文、valueGeneratorService);
    }
    捕获(例外情况除外)
    {
    var logger=services.GetService();
    logger.LogError(例如,“对数据库进行种子设定时发生错误”);
    }
    }
    }
    
    实际插入 这是使用通用存储库完成的,但归结起来是:

    Context.Set<T>().Add(entity);
    Context.SaveChanges();
    
    Context.Set().Add(实体);
    SaveChanges();
    

    问题:如何控制实体框架核心中内存中生成的键值?

    因此,JSON中的实体插入了它们拥有的任何ID。不起作用的是,当您插入新数据时,它们不会以新值(100000000)开始?@jpgrassi-是的,JSON实际上是具有“小”键的生产类数据的序列化(
    public const int StartValue = 100000000;
    
    class ResettableValueGenerator : ValueGenerator<int>
    {
        private int _current;
    
        public override bool GeneratesTemporaryValues => false;
    
        public override int Next(EntityEntry entry)
        {
            return Interlocked.Increment(ref _current);
        }
    
        public void Reset() => _current = StartValue;
    }
    
    
    public static void ResetValueGenerators(CustomApiContext context, IValueGeneratorCache cache, int startValue = StartValue)
    {
        var allKeyProps = context.Model.GetEntityTypes()
            .Select(e => e.FindPrimaryKey().Properties[0])
            .Where(p => p.ClrType == typeof(int));
        var keyProps = allKeyProps.Where(p => p.ValueGenerated == ValueGenerated.OnAdd);
    
        foreach (var keyProperty in keyProps)
        {
            var generator = (ResettableValueGenerator)cache.GetOrAdd(
                keyProperty,
                keyProperty.DeclaringEntityType,
                (p, e) => new ResettableValueGenerator());
    
            generator.Reset();
        }
    }
    
    private void InitializeSeeding(IServiceScope scope)
    {
        using (scope)
        {
            var services = scope.ServiceProvider;
            try
            {
                var context = services.GetRequiredService<CustomApiContext>();
    
                // this pushes deserialized data + static data into the database
                InitDbContext(context);
    
                var valueGeneratorService = services.GetRequiredService<IValueGeneratorCache>();
                ResetValueGenerators(context, valueGeneratorService);
            }
            catch (Exception ex)
            {
                var logger = services.GetService<ILogger<Startup>>();
                logger.LogError(ex, "An error occurred while seeding the database.");
            }
        }
    }
    
    Context.Set<T>().Add(entity);
    Context.SaveChanges();