Entity FrameworkとSQLiteとAUTOINCREMENT
本当はCodeFirstしたかったんだけど難しそうなので後回し。
Entity Data Modelデザイナを使えばおおかた簡単にできます。
AUTOINCREMENTキーワード
主キーには連番を使うことが多いですが、SQLiteにもそれを助ける機能が備わっています。
SQLiteにはAUTOINCREMENTというキーワードがありまして、テーブル作成するとき列にこれを指定しておくと、値を指定せずにレコード挿入することで連番を振ってくれます。仕組みとしてはsqlite_sequenceというテーブルに最後に生成した値が記録されていて、それに+1した値を振っているわけです。
またINTEGER PRIMARY KEYな列は先のキーワードを指定しなくても連番が生成されます。こちらはテーブルに存在する値の最大値+1が使われます。
これまではこの二つを気分で使い分けていたのですが、EntityFrameworkと組み合わせるとなるとそうもいかなかった、というお話。
StoreGeneratedPattern
挿入時に自動生成される列を扱うポイントは二つあります。
- 既定値をINSERTしない
既定値のつもりでも値を指定したら自動生成はされません。
- 自動生成された値が必要ならばINSERT後にSELECTする
INSERT文がレコード返してくれたら便利なのにね。
これをEntityFrameworkに教える方法としてStoreGeneratedPattern列挙体が用意されています。
http://msdn.microsoft.com/ja-jp/library/system.data.metadata.edm.storegeneratedpattern.aspx
EDMデザイナにも表示されます。
AUTOINCREMENTを付けていればこれをIdentityに設定するだけで上手いことやってくれます。
StoreGeneratedPatternとはなんだったのか
ところがAUTOINCREMENTがない場合はいくらStoreGeneratedPattern.Identityを指定しても
- 既定値をINSERTしない
- 自動生成された値が必要ならばINSERT後にSELECTする
といった動作をしてくれません。
edmxファイルを比べるとたった一行の違いでした。
<!--AUTOINCREMENTあり--> <Property Name="Id" Type="integer" Nullable="false" StoreGeneratedPattern="Identity" /> <!--AUTOINCREMENTなし--> <Property Name="Id" Type="integer" Nullable="false" />
AUTOINCREMENTがない時はデザイナで設定したStoreGeneratedPatternがSSDLに反映されていないという・・・
CSDLにもそれっぽい記述があって、こちらはAUTOINCREMENTなしでも反映されるのですが、これだけでは動作しないようです。
<Property Name="Id" Type="Int64" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
というわけでedmxを手動で直せばAUTOINCREMENTなしでも自動生成が使えましたとさ。めでたしめでたし。