EntityFrameworkはOleDBに非対応で事実上利用不可、UWPではついにSQLiteにその座を奪われたりと、もはや過去の遺物みたいな扱いを受けてるAccessですが、Windowsのちょろっとした業務アプリなんかには、未だに多く使われていることと思います。
何年か前に「AccessでEntityFrameworkは無理」という話をどこかしこで見たので、てっきり無理なものだと思い込んでいたんですが、偶々NuGetでJetEntityFrameworkなるものを見つけたので、試してみました。
今更EFなんて~と思う人も多いと思うんですが、Accessがネックになって、EFが今風に見えてる&だけど手の届かないもの、という人/現場/アプリも結構あると思うんですよね。 このJetEntityFrameworkが2015年にできて、未だにそれなりに更新されているあたり、Accessの根強い人気(?)根深い闇(?)を感じます。
Microsoft Access Entity Framework Provider - CodePlex
環境等
- Visual Studio 2015 Update3
- Access 2010(.accdb 2007-2010形式)
- JetEntityFrameworkProvider v1.2.6
作ってみる
新規プロジェクトの作成
- Windowsクラシックなアプリ(.Net 4.6.1)を新規作成します。 今回はC#&WPFを選んでいますが、Accessを用いたデスクトップアプリといえば、やっぱりVB&Windowsフォーム!という場合もご安心を。同じ手順で実装可能でした。
新規データベースの作成
- Accessからデータベースファイルを作成します。ここでは
C:\Temp\Main.accdb
に置きました。 この時点ではまだテーブルも何も存在しません。
ちなみにこのJetEntityFrameworkですがaccdbでなくmdbも対応しているそうです(OleDbでいけるから当然といえば当然)。
ライブラリインストール
NuGetパッケージマネージャを開き、JetEntityFramework
をインストールします。
(依存関係のEntityFramework6
は勝手についてきます。)
データベースの接続定義
App.config
に先ほど作成したAccessデータベースのConnectionStrings
を追記します。
MainConnection
の名前で作成しました。
<connectionStrings> <add name="MainConnection" connectionString="Provider=Microsoft.Ace.OleDb.12.0;Data Source = C:\Temp\Main.accdb" providerName="JetEntityFrameworkProvider"/> </connectionStrings>
POCO Entityクラスの作成
コードファーストなので、まずはモデルを表すコードを書きます。 クラス名がテーブル名、プロパティがフィールド名になります。
- 仮に商品マスターを分類管理するようなイメージで
Shohin``Bunrui
2つのEntity
クラスを作ってみます。
class Shohin { public int Sku { get; set; } public string Jan { get; set; } public string Name { get; set; } public decimal Price { get; set; } public virtual List<Bunrui> Bunrui { get; set; } } class Bunrui { public int Id { get; set; } public string Name { get; set; } public virtual List<Shohin> Shohin { get; set; } }
Contextクラスの作成
Entity
クラスとデータベースの橋渡しとなるのがコンテキストクラスです。
DbContext
を継承したContext
クラスを作成します。
System.Data.Entity
名前空間のクラスを使っていきます。
using System.Data.Entity;
- 継承元のコンストラクタに先ほどApp.configで定義した
MainConnection
を引数で渡すようにしておきます。 これで、このContext
クラスを使用する際に、接続情報として使用されます。 - Fluent APIを利用し、
OnModelCreating
メソッド内でShohin
クラスの主キーにSku
プロパティを指定しています。
(EFの規約ではプロパティ名がId
のものが主キーとされるため、Id
が無いShohin
クラスはこのままでは使えません。)
class Context:DbContext { public Context() : base("MainConnection") { } public DbSet<Shohin> Shohin { get; set; } public DbSet<Bunrui> Bunrui { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Shohin>() .HasKey( _ => _.Sku); } }
アプリ起動、テーブル生成
準備は整ったので、実際にテーブルが生成されるところを確認します。
- メインフォームのコンストラクタに、先ほどの
Context
クラスを使う処理を追記。とりあえず商品マスタの個数を数える感じで。
public MainWindow() { InitializeComponent(); using (var context = new Context()) { Console.WriteLine(context.Shohin.Count()); } }
アプリをビルド&実行します。 ここまでにミスが無ければ、さくっとアプリが立ち上がると思います。
Accessデータベースを見てみます。
Shohin
とBunrui
に多対多の関係を持たせたので、テーブルShohins
、Bubruis
、そして中間テーブルShohinBunruis
の3テーブルが作成されました。賢い! (ローマ字使ってしまったので勝手に複数形にされて残念なテーブル名になってます)