前兩篇博客學習了數據庫映射和表映射,今天學習下數據庫初始化、種子數據、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();
然后在數據庫中建一個視圖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();
四、執行存儲過程
有時候使用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); }
上面的都是查詢使用的都是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);
從上面截圖可以看到已經將personId=0003的Name改為CYW,之前都是cuiyanwei。