Как сохранить много связанных данных одновременно (сеялка пользовательской сборки) - PullRequest
0 голосов
/ 13 октября 2019

У меня есть веб-приложение .NET Core с базой данных EF Core (Code-First) на сервере. Мне нужно посеять кучу данных в базу данных сразу же при инициализации, потому что проект все еще находится в разработке.

Но я не могу уйти от этих исключений FOREIGN KEY SQL! Они похожи на дырявую трубу, каждый раз, когда я делаю изменения, чтобы исправить одну, появляется другая. И модели настолько взаимосвязаны, что много утечек. Мне нужно исправить их раз и навсегда.

У меня определены все мои модели и связи моделей, я использую библиотеку Bogus для C # для генерации данных, у меня есть весь код, написанный для создания фиктивных сущностейи связать их вместе так, как они должны быть.

Я не могу опубликовать свой точный код, потому что он проприетарный (я подрядчик), но я могу предоставить краткое описание того, что он делает:

  • Существует класс DbSeeder, который запускается при запуске приложения, если он еще не запускался. Здесь хранится логика заполнения базы данных. Обратите внимание, что я не использую какие-либо методы заполнения базы данных, описанные в документах MSFT - я не знал о них, когда писал пишущую систему, и сейчас я слишком глубоко разбираюсь.
  • У каждого объекта естьМетод GenerateBogus (), определенный в DbSeeder, который будет генерировать объект типа сущности и устанавливать все свойства в значения, предоставляемые Bogus, за исключением отношений, методы Bogus () не определены.
  • У меня естьединственный метод в DbSeeder, который вызывает методы Bogus () для каждого из типов сущностей, эффективно генерируя соответствующий объем поддельных данных для заполнения базы данных. Вот как выглядит этот метод:
// Generation of entities
var apples = GenerateBogusApples(5);
var bananas = GenerateBogusBananas(20);

// Add them to context
context.Apples.AddRange(apples);
context.SaveChanges();

context.Bananas.AddRange(bananas);
context.SaveChanges();

// Set up relationships
foreach (Bananas b in bananas)
{
    b.Apple = apples.Random();    // little pseudocode, hope you don't mind
}

// One final
context.SaveChanges();

// End result: A banana with an apple object associated with it
// My actual task is way more complicated, with lots of interdependency :/

Мне просто нужна база данных в состоянии, когда все фиктивные данные, которые я вставляю в нее, правильно связаны с соответствующими данными в соответствии с бизнес-логикой. Вместо этого я получаю много разных видов ошибок внешнего ключа, таких как «Оператор MERGE конфликтует с ограничением FOREIGN KEY».

1 Ответ

1 голос
/ 13 октября 2019

Вот несколько процедур, которые вы можете использовать для отключения (NOCHECK) всех внешних ключей и их повторного включения после загрузки:

create or alter procedure DisableAllConstraints 
as
begin
      DECLARE @sql nvarchar(max);

      DECLARE c CURSOR local read_only FOR
        SELECT 'ALTER TABLE '+ quotename(schema_name(t.schema_id))  + '.' + quotename(name) + ' NOCHECK CONSTRAINT ALL;'
        FROM sys.tables t
        where t.is_ms_shipped = 0
        and t.name <> 'sysdiagrams';

      OPEN c;
      FETCH NEXT FROM c INTO @sql;

      WHILE @@FETCH_STATUS = 0
      BEGIN                
        print @sql;
        exec (@sql);
        FETCH NEXT FROM c INTO @sql;
      END

      close c;
      deallocate c;
end

go

create or alter procedure EnableAllConstraints 
as
begin
      DECLARE @sql nvarchar(max);

      DECLARE c CURSOR local read_only FOR
      --use "with check check constraint all" to validate existing data _and_ enforce the constraint for new DML
      --use "check constraint all" to enforce the constraint but not check the existing data
        SELECT 'alter table '+ quotename(schema_name(t.schema_id))  + '.' + quotename(name) + ' with check check constraint all;'
      --SELECT 'alter table '+ quotename(schema_name(t.schema_id))  + '.' + quotename(name) + ' check constraint all;'
        FROM sys.tables t
        where t.is_ms_shipped = 0
        and t.name <> 'sysdiagrams';

      OPEN c;
      FETCH NEXT FROM c INTO @sql;

      WHILE @@FETCH_STATUS = 0
      BEGIN                
        print @sql;
        exec (@sql);
        FETCH NEXT FROM c INTO @sql;
      END

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