EntityFramework6 + SQLiteのCodeFirst(Migrationなし)

EF6+SQLiteでCodeFirstしたときに結構つまづいたのでメモ。
具体例がVBなのはホンマに申し訳ない。各々でC#に翻訳してください。

特に詰まったのが
* SQLiteのCodeFirstによるDB生成
  * 「テーブルが存在しません！」とかって怒られてた。それ作るのがCodeFirstの仕事ちゃうんかい
    * 結論から言うと、SQLiteのCodeFirstの場合は「データベースの生成すらプログラムに任せる」のが正解でした
    * そもそもEF6がSQLiteのCodeFirstに対応していないというのもあった
      * そのためのSQLite.CodeFirst
* 外部キーの連携と、CASCADE ON DELETE
  * 親レコードが削除されているのに、子レコードが削除されてずに残ってしまう問題
    * 結論から言うと、SQLite自身が標準でFKに対応していない。ConnectionString内で明示的に宣言することで対応可能
    
## NuGetでパッケージを取得
以下の三点が必要
* EntityFramework
* System.Data.SQLite.EF6
* SQLite.CodeFirst

EF6では、SQLiteのCodeFirstに標準では対応していないため、SQLite.CodeFirstパッケージにて対応。

## App.configの記述
### Providers
```
<provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
<provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
```

### ConnectionString
``` 	
<add name="DemoSqlite" connectionString="data source=local.db; foreign keys=true" providerName="System.Data.SQLite" />
```
* `data source`以下が、SQLiteのdbファイルが生成されるディレクトリ
  * **<B>ユーザー自身でデータベースを生成しないこと！</B>** SQLite.CodeFirstに任せる
* `foreign keys=true`、 **<B>SQLiteはForeignKeyの運用のために明示的な宣言が必要</B>**
* `providerName`、特に言うことなし。

### DbProviderFactories
```
<remove invariant="System.Data.SQLite.EF6" />
<add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
<remove invariant="System.Data.SQLite" />
<add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
```

## DbContextの配置
追加→新しい項目→ADO.NET Entity Data Model→空のCodeFirstモデル
任意のDbSetを配置。今回は1:nの関係を持つ親テーブル`User`と子テーブル`Posts`がある。

`OnModelCreating`メソッドをオーバーライドし、FluentAPIによるEFへの設定と、SQLiteCodeFirstによるDBの自動生成を記述する。

## OnModelCreatingのオーバーライド
先に全文 
``` vb
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
        ' テーブルすべての主キー（Id）の自動割り当てを解除する。
        modelBuilder.Entity(Of User)().Property(Function(us) op.us).HasDatabaseGeneratedOption(databaseGeneratedOption:=DatabaseGeneratedOption.None)

        modelBuilder.Entity(Of Post)().Property(Function(pt) pt.Id).HasDatabaseGeneratedOption(databaseGeneratedOption:=DatabaseGeneratedOption.None)

        ' Posts, picturesテーブルに対し、明示的にリレーションとON DELETE CASCADEを付与
        modelBuilder.Entity(Of Post)().HasRequired(Of User)(Function(pt) pt.User).WithMany(Function(us) us.Posts).WillCascadeOnDelete(True)

        ' DBが存在しない場合は生成する。(SQLiteのCodeFirstの場合は明示的に指示が必要)
        Dim sqliteConnectionInitializer = New SqliteCreateDatabaseIfNotExists(Of LocalUserService)(modelBuilder)
        Database.SetInitializer(sqliteConnectionInitializer)
End Sub
```
「自動割り当てを～うんぬんかんぬん」は無視してもらって良い。（一応、EF側でIDの自動付番を行わないための設定である）

### リレーションとCASCADEの明示的な宣言
``` vb
modelBuilder.Entity(Of Post)().HasRequired(Of User)(Function(pt) pt.User).WithMany(Function(us) us.Posts).WillCascadeOnDelete(True)

```
PostのEntityは、UserのEntityを.UserをkeyとしてRequiredし、UserEntityからは.Postsをコレクションkeyとして1:nの関係を持っており、ON DELETE時はCASCADEする。
と、書いてる。
実際のところ、明示的に書かなくてもEFがいい感じにしてくれる事が多いが、今回はうまくいかなかったので明示的な宣言を行った。
（のちに、SQLite自身が、デフォルトでForeignKeyに対応しないことが判明。そのためのConnectionStringの記述）

ちなみに、このリレーションの関係は逆の目線（n:1）からでも書ける。
``` vb

= modelBuilder.Entity(Of User)().HasMany(Function(us) us.Post).WithRequired(Function(pt) pt.User).WillCascadeOnDelete(True)
```

### SQLite.CodeFirstの設定
``` vb
 Dim sqliteConnectionInitializer = New SqliteCreateDatabaseIfNotExists(Of LocalUserService)(modelBuilder)

Database.SetInitializer(sqliteConnectionInitializer)
```
`SqliteCreateDatabaseIfNotExists`クラスがSQLite.CodeFirstの要。こやつをInitializerとして渡す。
名の通り、「DBが存在しないときに生成」を行う。
他にも「常時DBをDropし、新規作成する」と「モデルが変更された場合のみDBをDropして新規作成する」というクラスが用意されている上で、ユーザによる任意の設定も可能、らしい。

以上で、DbContextのインスタンス生成時に、DbSet（クラス）に基づいたDBが生成される。