Как управлять значениями ключей, генерируемых в памяти, в Entity Framework Core? - PullRequest
4 голосов
/ 27 мая 2019

Фон

Я занимаюсь разработкой веб-приложения на основе ASP.NET Core 2.1 и EntityFrameworkCore 2.1.1.Помимо других типов тестов, я использую тестирование InMemory Web API , чтобы провести какое-то интеграционное тестирование Web.Api.

Поскольку тестовые данные довольно запутанны, я создал файл JSONна основе фрагмента перенесенной базы данных тестирование импортирует данные из этого файла JSON, когда запускаются тесты в памяти.

Проблема

Тесты только для чтения работают очень хорошо.Тем не менее, когда я вставляю что-то для сущности, которая имеет идентичность (ValueGenerated == ValueGenerated.OnAdd), она автоматически получает значение 1 (все PK имеют значение int s).Это имеет смысл, поскольку любой генератор EF, используемый за сценой для генерации этих значений, не был проинструктирован для генерации из определенного значения.

Однако, это явно не работает должным образом для вставок, которые генерируют существующее значение ключа.

То, что я пробовал

  1. [текущее рабочее решение] Сдвиг значений ключа - После десериализации всех объектов я выполняю операции сдвига идентификаторов для всех задействованных объектов (они получают "большие" значения).Это работает должным образом, но это подвержено ошибкам (например, некоторые объекты имеют статические идентификаторы, я должен убедиться, что все внешние ключи / свойства навигации определены правильно, и сейчас это довольно медленно, так как я полагаюсь на отражение, чтобы правильно идентифицировать ключи /свойства навигации, требующие смещения)

  2. Настройка генератора значений для запуска с большого значения :

TestStartUp.cs

services.AddSingleton<IValueGeneratorCache, ValueGeneratorCache>();
services.AddSingleton<ValueGeneratorCacheDependencies, ValueGeneratorCacheDependencies>();

Функциональность генерации идентификаторов

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();

Вопрос: Как управлять значениями ключей, генерируемых в памяти, в Entity Framework Core?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...