###### tags: `Entity Framework` `Upload Notion Done` # DB EF(6):SQLLite Code First 近期專案使用EF6操作SQLLite並做Code First踩一些坑,特別紀錄一下實作過程。目前針對EF6,官方沒太多文件,大都是網路較散落的文章。另外EF6 SQLLite操作上,大多數人使用DB First的居多。因為以Code First角度設計上,目前EF Core會較成熟(坑較少) 操作方法有兩種 - Migration:會使用Migration套件,可透過Migration做DB版本管控。但目前用起來在Multi Context以及跟SQL Server混用會有些無預期問題。另外就是會遇到Migration不支援的語法->[參考](https://shioulo.eu5.org/node/30)。 - Code First:使用Code First套件中的SqliteDropCreateDatabaseWhenModelChanges方法,在EF Model改變及Context執行時會去自動生成Table。但目前唯一缺點就是在EF Model改變時,他會重新Gen Table照成原本資料被刪除..所以不適合拿來做主DB使用情境。 # Demo Code [Demo Code點我,在SQLLiteDemo](https://github.com/spyua/hackmdDocCode/tree/main/SQLLiteDemo) # 使用Net版本 - DeskTop .Net NetFramework 4.8 # 一、使用套件 - EntityFramework 6.4.4 - System.Data.SQLite 1.0.116(安裝時會同步安裝以下套件) - Stub.System.Data.SQLite.Core.NetFramework - System.Data.SQLite.Core - System.Data.SQLite.Linq - System.Data.SQLite.EF6 ## Code First Solution (不做Migration) - SQLite.CodeFirst 1.7.0.34 ## 可做Migration - System.Data.SQLite.EF6.Migrations 1.0.112 # 二、Config設置 ## Provider設定 基本上在System.Data.SQLite安裝完後,App Config會幫你設置完,會呈現如下,但**你要自行加入Provider設定**(紅框處-點擊圖片可放大) ![](https://i.imgur.com/hBZQcFv.png) ```csharp <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" /> ``` ## Connection設定 ```csharp <connectionStrings> <add name="Your Conection Alias Name" connectionString="data source=yourdbName.db" providerName="System.Data.SQLite" /> </connectionStrings> ``` # 三、設定Entity Model 接著開始設計你的DB Model ```csharp [Table("TestTable")] public class TestTable { [Required] [Key] public Guid Id { get; set; } [StringLength(100)] public string Content { get; set; } } ``` # 四、DB Context,Configure撰寫與Demo ## Code First版本 Code First只需要在TestContext去複寫OnModelCreating,並使用SqliteDropCreateDatabaseWhenModelChanges的方法。範例Code如下。 ```csharp public class TestContext : DbContext { private static readonly bool[] s_migrated = { false }; public DbSet<TestTable> TestTables { get; set; } public TestContext() : base("LocalDBConn") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { if (!s_migrated[0]) { lock (s_migrated) { if (!s_migrated[0]) { var initializer = new SqliteDropCreateDatabaseWhenModelChanges<TestContext>(modelBuilder); Database.SetInitializer(initializer); s_migrated[0] = true; } } } } } ``` 實際Demo如下圖 ![](https://i.imgur.com/FGlUdvG.png) 你可以嘗試更改Table Name將Content改成Contents,此時再重新開啟程式,就會發現原本的資料不見了。另外需注意!!!!!!!! 目前看起來EF Model屬性設Index會有問題,詳細還不清楚為什麼。有興趣可以自行Try。 ## Migration版本 一樣一開始寫Context,但我們不需要額外在OnModelCreating做額外設定 ```csharp public class TestContext : DbContext { public DbSet<TestTable> TestTables { get; set; } public TestContext() : base("LocalDBConn") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { } } ``` 此時在SQL Server版本,我們就可以下Enable-Migration產生Configure檔案,但SQL Lite版本有點秀逗,所以這邊我們可以自行撰寫Configure如下,可以看到Configure需額外設定SqlGenerator,並注入System.Data.SQLite.EF6.Migrations的SQLiteMigrationSqlGenerator ```csharp public class Configuration : DbMigrationsConfiguration<TestContext> { public Configuration() { // 需自行設定 AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; // Gen SQL Lite Migration this.SetSqlGenerator("System.Data.SQLite", new SQLiteMigrationSqlGenerator()); } protected override void Seed(TestContext context) { // This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method // to avoid creating duplicate seed data. } } ``` 此時就可以下Add-Migration指令,只是注意!在Multi Context會有些小問題,[詳細請點我](https://hackmd.io/@spyua/ryn54i7i9) 最保險的方法,可以先將要產Migration的專案設為起始專案就萬無一失,也比較方便。Migration結果如下 ![](https://i.imgur.com/C19zpZv.png) 接著下Update-Database就可以產出SqlLite DB了, ![](https://i.imgur.com/YIaDTrs.png) ![](https://i.imgur.com/XBR3Sq6.png)