mikeo_410


SQLite の dbml

  「System.Data.Sqlite、Linq」「LINQ to SQL クラスの自動生成」から、既製品による自動生成は諦めることにします。作成するとして、何を生成すれば良いか確認して置きます。

1.プロジェクトの準備

  1. System.Data.SQLite を使います。インストールして置きます。
  2. WPF アプリケーション・プロジェクトを作ります。WpfApplication3 が出来ました。
  3. 「参照の追加」で、System.Data.SQLite、System.Data.SQLite.Linq を追加します。
  4. Window1.xaml の <Grid> に Loadedイベントを設定します。
  5. イベントハンドラを自動生成し、このハンドラに下記のテスト用のコードを書いて置きます。(この段階では、当然エラーになります。)
    1. private void Grid_Loaded(object sender, RoutedEventArgs e)
    2. {
    3.     DataClasses1DataContext db = new DataClasses1DataContext();
    4.     var rows2 = from t1 in db.Table_1 select new { t1.title, t1.Table_2.content };
    5.     foreach (var o in rows2)
    6.         Debug.WriteLine(o.title + " " + o.content);
    7. }
  6. もし、Windows x64 を使っているなら、「構成マネージャー」で「ソリューションプラットフォーム」を「Any CPU」から「x86」に変えておくことが必要です。 

2.テストデータの用意


  2つのテーブルがあり、表題(title)と本文(content)が別のテーブルにあります。content_id で繋がっています。

  SQLite Database Browser.exe と言うソフトでデータベース、テーブルを作り、少しだけデータを入れて置きました。

  左図は、これから作る dbml を Visual Studio で開いたときの表示です。

  フィールドの型ですが、title と content は TEXT です。
  idは、INTEGER PRIMARY KEY です。
  content_id は、Table_1 が Numeric、Table_2 が INTEGER PRIMARY KEY です。

  SQLite のデータベースは、TEXT、NUMERIC、BLOB,INTEGER PRIMARY KEY が識別されるだけで、型を持たない発想からできているようです。
  データベースからテーブルの情報を取得すると、テーブルを生成した時のSQL文が返されます。
  それ以上詳しい情報は無いようです。

3.dbml の作成

  DataClasses1.dbml を以下の内容で作成しました。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Database Name="sample" Class="DataClasses1DataContext" xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
  3.   <Connection Mode="ConnectionString" ConnectionString="DbLinqProvider=Sqlite; Data Source=sample.sqlite" SettingsObjectName="WpfApplication3.Properties.Settings" Provider="System.Data.Sqlite" />
  4.   <Table Name="Table_1" Member="Table_1">
  5.     <Type Name="Table_1">
  6.       <Column Name="id" Type="System.Int64" DbType="BigInt NOT NULL" CanBeNull="false" />
  7.       <Column Name="title" Type="System.String" DbType="NVarChar(50) NOT NULL" CanBeNull="false" />
  8.       <Column Name="content_id" Type="System.Int64" DbType="BigInt NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
  9.       <Association Name="Table_2_Table_1" Member="Table_2" ThisKey="content_id" OtherKey="content_id" Type="Table_2" IsForeignKey="true" />
  10.     </Type>
  11.   </Table>
  12.   <Table Name="Table_2" Member="Table_2">
  13.     <Type Name="Table_2">
  14.       <Column Name="content_id" Type="System.Int64" DbType="BigInt NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
  15.       <Column Name="content" Type="System.String" DbType="NVarChar(MAX)" CanBeNull="true" />
  16.       <Association Name="Table_2_Table_1" Member="Table_1" ThisKey="content_id" OtherKey="content_id" Type="Table_1" Cardinality="One" />
  17.     </Type>
  18.   </Table>
  19. </Database>

   これは、ゼロから書いたわけではなく、SQL Server で、同じ形式のテーブルを作って、自動生成したものを修正しました。
  変更は、最初の方の<Connection>の内容です。
  フィールドの型がそれらしく入っていますが、前述の通り、SQLite には型がほとんどないのであまり意味がありません。

4.プロジェクトに追加

   ソリューションエクスプローラの窓で、プロジェクトを選択し、右ボタンメニューから「追加」「既存の項目」で、DataClasses1.dbml を追加します。

  自動的に、DataClasses1.designer.cs、DataClasses1.dbml.layout が生成されます。

  これで、ビルドできるようになります。
  ただし、1つだけ問題が残っています。

  System.Data.Linq.DataContex のコンストラクタでは、SQLight のデータベースが開けないと言うものです。
  接続文字列が指定された場合、プロバイダの指定があれば、それを使うのが予定の行動だと思うのですが、実際は SQLiteConnection を直接呼び出す必要があります。

  方法は2つあります。1つは、DataClasses1.designer.cs を変更するもので、他方はテスト用のコードの修正です。

  下記は、DataClasses1.designer.cs の最初の方にある、DataClasses1DataContext クラスのコンストラクタの1つ(引数なしのコンストラクタ)です。

  1. public DataClasses1DataContext() : 
  2.         base("DbLinqProvider=Sqlite; Data Source=sample.sqlite", mappingSource)
  3. {
  4.     OnCreated();
  5. }

  これを、以下のように修正します。これで、正常にテスト用のコードが実行できました。

  1. public DataClasses1DataContext() : 
  2.         base(new System.Data.SQLite.SQLiteConnection("DbLinqProvider=Sqlite; Data Source=sample.sqlite"), mappingSource)
  3. {
  4.     OnCreated();
  5. }

  また、DataClasses1.designer.cs を修正する代わりに、テスト用のコードを以下のように修正しても OK です。
  コネクションを引数に持つ、コンストラクタを呼び出します。

  1. private void Grid_Loaded(object sender, RoutedEventArgs e)
  2. {
  3.     System.Data.IDbConnection con
  4.         =new System.Data.SQLite.SQLiteConnection("DbLinqProvider=Sqlite; Data Source=sample.sqlite");
  5.     DataClasses1DataContext db = new DataClasses1DataContext(con);
  6.     var rows2 = from t1 in db.Table_1 select new { t1.title, t1.Table_2.content };
  7.     foreach (var o in rows2)
  8.         Debug.WriteLine(o.title + " " + o.content);
  9. }


mikeo_410@hotmail.com