EF实体框架之CodeFirst三

时间:2021-01-03 08:52:21

前两篇博客学习了数据库映射和表映射,今天学习下数据库初始化、种子数据、EF执行sql以及执行存储过程这几个知识。

一、数据库初始化策略

数据库初始化有4种策略

策略一:数据库不存在时重新创建数据库

Database.SetInitializer<EFCodeFirstDbContext>(new CreateDatabaseIfNotExists<EFCodeFirstDbContext>());

策略二:每次启动应用程序时创建数据库

Database.SetInitializer<EFCodeFirstDbContext>(new DropCreateDatabaseAlways<EFCodeFirstDbContext>());

策略三:模型更改时重新创建数据库

Database.SetInitializer<EFCodeFirstDbContext>(new DropCreateDatabaseIfModelChanges<EFCodeFirstDbContext>());

策略四:从不创建数据库

Database.SetInitializer<EFCodeFirstDbContext>(null);

其中,在使用每次启动应用程序时创建数据库DropCreateDatabaseAlways时,总是报错:无法删除数据库XXX,因为该数据库当前正在使用,这个错误找了半天,在一篇帖子上写让选中数据库,右键删除,只选关闭连接复选框,之后就可以了,我也试了下,是可以的。

二、种子数据

对于新建的数据库,可能会有一些默认的数据来做测试或默认配置,这时可以使用种子类来初始化数据库数据。加入使用的是DropCreateDatabaseAlways策略,那么初始化器类就要从该泛型类继承,并传入数据库上下文作为类型参数。接下来,要种子化数据库就要重写DropCreateDatabaseAlways类的Seed方法,而Seed方法拿到了数据库上下文,因此我们可以使用它来将数据插入数据库:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EFCodeFirstModels;

namespace EFCodeFirstDataAccess
{
public class SeedingDataInitializer: DropCreateDatabaseAlways<EFCodeFirstDbContext>
{
protected override void Seed(EFCodeFirstDbContext context)
{
Person person
= new Person("0002","cuiyanwei",SexType.Female,26);
Person person1
= new Person("0003", "cuiyanwei1", SexType.Female, 25);
context.Persons.Add(person);
context.Persons.Add(person1);
base.Seed(context);
}
}
}

上面的代码中并没有SaveChanges(),然后将将数据库初始化器类用于数据库上下文类

        public EFCodeFirstDbContext() : base("MyStrConn")
{
Database.SetInitializer
<EFCodeFirstDbContext>(new SeedingDataInitializer());
}

此时初始化种子,就不能在OnModelCreating中执行数据库初始化策略了。

Database.SetInitializer<EFCodeFirstDbContext>(new DropCreateDatabaseAlways<EFCodeFirstDbContext>());

三、执行SQL语句

有时候在code first中也会执行sql来做查询,或者是查询视图。

            //using能及时释放资源,例如数据库连接异常,可以即使将上下文释放
using (var db=new EFCodeFirstDbContext())
{
List
<Person> persons= db.Database.SqlQuery<Person>("select * from Person where personId=@id",new SqlParameter("@id","0002")).ToList();
foreach (var person in persons)
{
Console.WriteLine(
"{0} {1} {2} {3}",person.PersonId,person.Name,person.Age,person.Sex);
}
}
Console.ReadLine();

EF实体框架之CodeFirst三

然后在数据库中建一个视图TestView,不过查询的还是Person,其实也可以查询部分字段,那样还要再创建Model,因为懒所以还是使用Person。此时我们就不能使用DropCreateDatabaseAlways策略模式了,这样的话数据的视图这些都会不存在。我们可以使用CreateDatabaseIfNotExists策略模式,初始化数据时只需把SeedingDataInitializer类继承自CreateDatabaseIfNotExists就OK了。

            //using能及时释放资源,例如数据库连接异常,可以即使将上下文释放
using (var db=new EFCodeFirstDbContext())
{
List
<Person> persons= db.Database.SqlQuery<Person>("select * from TestView where personId=@id", new SqlParameter("@id","0002")).ToList();
foreach (var person in persons)
{
Console.WriteLine(
"{0} {1} {2} {3}",person.PersonId,person.Name,person.Age,person.Sex);
}
}
Console.ReadLine();

EF实体框架之CodeFirst三

四、执行存储过程

有时候使用sql能解决的问题使用ef就不那么简单,比如查找树的某个节点的所有父节点或所有子节点。如果使用存储过程那就会很容易,不过存储过程也有弊端,例如只能返回一个表,不能同时返回多个表,可能是有我没找到吧。

CREATE PROCEDURE TestProcedure
@personId nvarchar(
100)
AS
BEGIN
select * from Person where PersonId=@personId;
END
GO

上面创建一个有一个参数的存储过程,来查询person。

                List<Person> persons = db.Database.SqlQuery<Person>("TestProcedure @personId", new SqlParameter("@personId", "0003")).ToList();
foreach (var person in persons)
{
Console.WriteLine(
"{0} {1} {2} {3}",person.PersonId,person.Name,person.Age,person.Sex);
}

EF实体框架之CodeFirst三

上面的都是查询使用的都是SqlQuery,如果需要更新操作可以使用ExecuteSqlCommand方法。

               int count=  db.Database.ExecuteSqlCommand("update Person set Name=@name where PersonId=@personId",new[] { new SqlParameter("@name", "CYW"), new SqlParameter("@personId", "0003") });
Console.WriteLine(count);

EF实体框架之CodeFirst三

从上面截图可以看到已经将personId=0003的Name改为CYW,之前都是cuiyanwei。