当前位置: 代码迷 >> 综合 >> EntityFramework--数据库初始化的类别与作用讲解
  详细解决方案

EntityFramework--数据库初始化的类别与作用讲解

热度:99   发布时间:2023-11-06 20:27:11.0

文章目录

      • 1,CreateDatabaseIfNotExists
      • 2,DropCreateDatabaseIfModelChanges
      • 3,DropCreateDatabaseAlways
      • 4,CustomInitializer
      • 5,Null
      • 6,static 构造器

使用 EntityFramework 初始化数据库是必要的。它创建数据库、表和所有约束。当context指定数据库初始化自身或向数据库添加实体时,可以生成数据库。但是,当数据库存在并且我们更改了模型类时,我们如何控制数据库模式的更改?这就是本文的目标。我们将看到如何控制 EntityFramework 来创建,特别是如何更新数据库模式。

我们已经看到了默认的初始化器。它被命名为CreateDatabaseIfNotExists。这只有在您启动一个全新的应用程序时才有趣。原因是,像向类添加新属性这样的小更改会引发异常。因为 EntityFramework 意识到代码中的模型不再与表模式同步。结果是一个InvalidOperationException

Additional information: The model backing the ‘YourContext’ context has changed since the database was created. Consider using Code First Migrations to update the database.
附加信息:自数据库创建以来,支持“YourContext” context 的模型已经更改。考虑使用代码优先迁移来更新数据库。

1,CreateDatabaseIfNotExists

如果您想使用这种类型的初始化器,您必须手动删除整个数据库,以便对上下文进行每次修改。对于您的信息,默认的intializer也可以在DbContext的构造器中显式地指定。

public class EmployeeDBContext:DbContext
{public YourContext(): base("EmployeeDBContext"){Database.SetInitializer<EmployeeDBContext>(new CreateDatabaseIfNotExists<EmployeeDBContext>()); }public DbSet<Department> Departments { get; set; }public DbSet<Employee> Employees { get; set; }
}

2,DropCreateDatabaseIfModelChanges

为了让你不必每次都删除数据库,您可以使用第二个初始化器,如果检测到任何更改,它将为您删除数据库。第二个初始化器是DropCreateDatabaseIfModelChanges。

public class EmployeeDBContext:DbContext
{public EmployeeDBContext(): base("EmployeeDBContext"){Database.SetInitializer<EmployeeDBContext>(new DropCreateDatabaseIfModelChanges<EmployeeDBContext>()); }public DbSet<Department> Departments { get; set; }public DbSet<Employee> Employees { get; set; }
}

3,DropCreateDatabaseAlways

需要注意的是,如果您不更改模型,该初始化器将不会删除数据库。如果您多次运行您的应用程序,它可能会开始拥有大量您可能不想要的数据。在这种情况下,即使不更改模型,您也希望删除数据库中的所有数据,然后你就不得不使用第三个初始化器。每当应用程序启动时,DropCreateDatabaseAlways删除数据库。

public class EmployeeDBContext:DbContext
{public EmployeeDBContext(): base("EmployeeDBContext"){Database.SetInitializer<EmployeeDBContext>(new DropCreateDatabaseAlways<EmployeeDBContext>());}public DbSet<Department> Departments { get; set; }public DbSet<Employee> Employees { get; set; }
}

4,CustomInitializer

以上所有这些初始化器的问题是,它们在某个时候都让您失望了。就是必须使用SQL脚本初始数据填充表。这也是初始化器存在 的 最有意义的地方之一。它就是自定义初始化器。您可以创建自己的初始化器,并从我们刚才讨论的三种初始化器之一继承。例如,您可以在每次模式更改时删除所有数据库,这将创建所有表,并且也在这个自定义初始化器中告诉 EntityFramework 插入默认的演示值。您还可以创建一个并不继承这三个中的任何一个,而是继承自IDatabaseInitializer的类。继承现有初始化器的优点是,您可以利用基本功能,只重写Seed方法将数据推入网站。

如下这个自定义初始化器 还解决了一个问题,就是当你调用DropCreateDatabaseAlways初始化器的时候,可能会遇到一个问题,那就是数据库正在使用中,不让你删除,Can not drop database because it is currently in use,如下解决了你的问题。
当活动连接仍然连接到正在删除的数据库时,就会发生此问题。一个技巧是覆盖InitializeDatabase方法并去alter the database。这将告诉数据库关闭所有连接,如果事务打开,则回滚该事务。

    public class CustomInitializer<T> : DropCreateDatabaseAlways<EmployeeDBContext>{public override void InitializeDatabase(EmployeeDBContext context){context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, string.Format("ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", context.Database.Connection.Database));base.InitializeDatabase(context);}protected override void Seed(EmployeeDBContext context){// Seed code goes here...base.Seed(context);}}
  public class EmployeeDBContext:DbContext{public DbSet<Department> Departments { get; set; }public DbSet<Employee> Employees { get; set; }public EmployeeDBContext() : base("EmployeeDBContext"){Database.SetInitializer<EmployeeDBContext>(new CustomInitializer<EmployeeDBContext>()); }}

自定义初始化器方法重写Seed 方法。在这里,你可以使用context参数去向你的database中插入数据。您不必调用SaveChanges来保存任何东西,因为调用seed方法的类在调用了seeding方法之后会立即调用SaveChanges。

5,Null

最后一个配置是清除所有初始化。这不会检查数据库是否更改,也不会同步表和模型类之间的差异。如果您有一个现有的数据库,而 entity framework 无法处理 创建和插入初始值的操作,那么这是非常理想的。默认貌似第一次还是如果没有会创建。

public class EmployeeDBContext:DbContext
{public EmployeeDBContext(): base("EmployeeDBContext"){Database.SetInitializer<EmployeeDBContext>(null); //No initialization}public DbSet<Department> Departments { get; set; }public DbSet<Employee> Employees { get; set; }
}

6,static 构造器

在结束之前,我必须说明任何初始化器都应该在context的静态构造函数中设置。静态构造函数在任何构造函数之前调用,并且只执行一次。这就是我们想要的。原因是,在某些应用程序中,可以多次初始化 context。但是你绝对不希望所有进程都来检查数据库是否是需要更改的

static YourContext()
{//Database.SetInitializer<YourContext>(new CreateDatabaseIfNotExists<YourContext>()); //Default one//Database.SetInitializer<YourContext>(new DropCreateDatabaseIfModelChanges<YourContext>()); //Drop database if changes detected//Database.SetInitializer<YourContext>(new DropCreateDatabaseAlways<YourContext>()); //Drop database every times//Database.SetInitializer<YourContext>(new CustomInitializer<YourContext>()); //Custom if model changed and seed valuesDatabase.SetInitializer<YourContext>(null); //Nothing is done
}

我们已经了解了如何使用 EntityFramework 来初始化数据库,以及如何使用测试值对其进行seed。我们已经了解了许多不同的方法来使用EntityFramework初始化数据库、表和模型类。到目前为止,我们还没有讨论用EntityFramework的迁移工具来初始化数据库。该工具允许使用实体对数据库进行手动调用来执行初始化。它的优点是完全控制什么时候做什么事情,缺点是有更多的事情要做。关于迁移工具的信息将在后面讨论。

文章翻译转载自Patrick Desjardins Blog,点击链接进入