如何一次保存大量相关数据(自定义种子)

时间:2019-10-13 17:53:47

标签: c# sql-server entity-framework

我有一个.NET Core Web应用程序,其后端具有EF Core(代码优先)数据库。我需要在初始化时立即将一堆数据播种到数据库中,因为该项目仍在开发中。

但是我无法摆脱这些FOREIGN KEY SQL异常!它们就像一个漏水的管道,每当我进行更改以修复它时,都会弹出另一个。而且这些模型之间的联系是如此之多,以至于泄漏很多。我需要一劳永逸地修复它们。

我已经定义了所有模型和模型关系,正在使用Bogus库进行C#生成数据,编写了所有代码来创建虚假实体并将它们按照应有的方式捆绑在一起。 / p>

我无法发布确切的代码,因为它是专有的(我是承包商),但是我可以提供它的摘要:

  • 如果以前没有运行过DbSeeder类,则该类将在应用程序启动时运行。这是存储数据库种子逻辑的位置。请注意,我没有使用MSFT文档中描述的任何数据库播种方法-编写播种器时我还不了解它们,而我现在太深了。
  • 每个实体在DbSeeder中定义了一个GenerateBogus()方法,该方法将生成该实体类型的对象并将所有属性设置为Bogus提供的值(关系除外),Bogus()方法未定义任何关系。 / li>
  • 我在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 个答案:

答案 0 :(得分:1)

您可以使用以下两个步骤来禁用(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