DataSource for Entity Framework for WinForms
LiveLinq と宣言型プログラミング
C1LiveLinq > LiveLinq の開始 > LiveLinq と宣言型プログラミング

LiveLinq によって提供されるライブビューは、データ連結シナリオに限定されません。

ライブビューを使用して、複数のテーブルから取得したデータを組み合わせ、このデータをビジネスルールに従ってグループ化して集計し、さらにすべての時点でアプリケーションから使用可能にします。ビューは常にデータと同期化されており、データが必要なときに何らかのメソッドを呼び出してビューを更新する必要はありません。これにより、アプリケーションロジックが大きく簡略化され、効率が向上します。

この点を具体的に説明するために、次のサービスを公開する NorthWind アプリケーションを考えます。

ProcessOrder:このサービスは、顧客に課金し、製品を出荷し、またデータベース内の情報を更新します。これは、営業部門および自社の Web ストアで使用されます。

SalesInformation:このサービスは、製品および製品カテゴリごとの売上の要約を返します。管理部門とマーケティング部門で使用されます。

ProcessOrder サービスで注文を直接データベースに書き込み、SalesInformation サービスで最新の販売サマリーを返すストアドプロシージャを実行することで、このアプリケーションを実装できます。これでも機能しますが、SalesInformation サービスは毎回データベースにアクセスし、データベース内のすべての注文をスキャンするため、比較的大きな負荷が発生します。

別のアプローチとして、データをライブビューにロードし、そこで注文の処理に従って販売サマリーを常に最新の状態を維持する方法があります。ProcessOrder メソッドを呼び出すと、SalesInformation によって提供されるサマリーが自動的に更新されます。SalesInformation の呼び出しは、データベースにまったくアクセスすることなく、即座に処理されます。

これを説明するために、再度 NorthWind データを使用して、別の単純な WinForms アプリケーションを作成します。このアプリケーションには3つのグリッドを置きます。最初の1つは ProcessOrder サービスに対応するグリッドで、注文を編集するために使用されます。他の2つは SalesInformation サービスに対応するグリッドで、販売サマリーが常に注文に同期して表示されます。

手順は次のとおりです。

  1. 新しい WinForms アプリケーションを作成します。
  2. [データ]→[新しいデータソースの追加]メニューを使用して、NORTHWND.MDF データベースへの参照を追加します。ウィザードに表示されるデフォルトのオプションをすべて受け入れ、さらにデータベース内のテーブルをすべて選択します。
  3. プロジェクトに C1.LiveLinq.dll アセンブリへの参照を追加します。
  4. 次の図に示すように、3つの DataGridView コントロールをフォームに追加し、それぞれの上にラベルを置きます。

次に、フォームを右クリックし、次のコードを入力します。

C#
コードのコピー
using C1.LiveLinq;
using C1.LiveLinq.AdoNet;
using C1.LiveLinq.LiveViews;
 
public Form1()
{
  InitializeComponent();
 
  // データを取得します
  NORTHWNDDataSet ds = GetData();
 
  // 受注明細を更新するためのライブビューを作成します
  this.dataGridView1.DataSource = GetOrderDetails(ds);
 
  // 最新の受注情報を提供するライブビューを作成します
  this.dataGridView2.DataSource = GetSalesByCategory(ds);
  this.dataGridView3.DataSource = GetSalesByProduct(ds);
}

前と同様に、最初の手順ではデータベースから関連データをロードします。

C#
コードのコピー
NORTHWNDDataSet GetData()
{
  var ds = new NORTHWNDDataSet();
  new NORTHWNDDataSetTableAdapters.ProductsTableAdapter()
    .Fill(ds.Products);
  new NORTHWNDDataSetTableAdapters.Order_DetailsTableAdapter()
    .Fill(ds.Order_Details);
  new NORTHWNDDataSetTableAdapters.CategoriesTableAdapter()
    .Fill(ds.Categories);
  return ds;
}
   

次に、LiveLinq を使用して、SalesInformation サービスから公開されるライブビューを実装します。これは標準の LINQ クエリーです。ただし、標準のクエリーをライブビューに変換するための2つの AsLive 節があり、以前のサンプルで使用した LINQ クエリーより多少高度になっています。

C#
コードのコピー
object GetSalesByCategory(NORTHWNDDataSet ds)
{
  var products = ds.Products;
  var details = ds.Order_Details;
  var categories = ds.Categories;
  var salesByCategory =
    from p in products.AsLive()
    join c in categories.AsLive()
      on p.CategoryID equals c.CategoryID
    join d in details.AsLive()
      on p.ProductID equals d.ProductID
    let detail = new
    {
      CategoryName = c.CategoryName,
      SaleAmount = d.UnitPrice * d.Quantity
        * (decimal)(1f - d.Discount)
    }
    group detail
      by detail.CategoryName into categorySales
    let total = categorySales.Sum(x => x.SaleAmount)
    orderby total descending
    select new
    {
      CategoryName = categorySales.Key,
      TotalSales = total
    };
  return salesByCategory;
}

クエリーは、最初に、それぞれ製品、カテゴリ、注文の情報が格納された3つのテーブルを結合します。次に、各受注明細の製品カテゴリと合計額を保持する一時変数 detail を作成します。最後に、明細を総売上に基づいて並べ替え、カテゴリ名でグループ化します。

結果は、基底のデータが変化したときに自動的に更新されるライブビューになります。これは、すぐ後に、アプリケーションを実行して確認します。

次のライブビューは、カテゴリごとではなく、製品ごとに販売情報を提供する点を除けば同じです。

C#
コードのコピー
object GetSalesByProduct(NORTHWNDDataSet ds)
{
  var products = ds.Products;
  var details = ds.Order_Details;
  var categories = ds.Categories;
 
  var salesByProduct =
    from p in products.AsLive()
    join c in categories.AsLive()
      on p.CategoryID equals c.CategoryID
    join d in details.AsLive()
      on p.ProductID equals d.ProductID
    into sales
    let productSales = new
    {
      ProductName = p.ProductName,
      CategoryName = c.CategoryName,
      TotalSales = sales.Sum(
         d => d.UnitPrice * d.Quantity *
              (decimal)(1f - d.Discount))
    }
    orderby productSales.TotalSales descending
    select productSales;
 
  return salesByProduct;
}
最後のビューは、受注明細を表示します。このビューを編集可能なグリッドに連結して、作成中または変更中の注文や、変更が以前のビューに及ぼす影響をシミュレートできます。
C#
コードのコピー
object GetOrderDetails(NORTHWNDDataSet ds)
{
  var products = ds.Products;
  var details = ds.Order_Details;
  var categories = ds.Categories;
 
  var orderDetails =
    from d in details.AsLive().AsUpdatable()
    join p in products.AsLive()
      on d.ProductID equals p.ProductID
    join c in categories.AsLive()
      on p.CategoryID equals c.CategoryID
    select new
    {
      c.CategoryName,
      p.ProductName,
      d.UnitPrice,
      d.Quantity,
      d.Discount
    };
 
  return orderDetails;
}

ここでアプリケーションを実行すると、次のようなウィンドウが表示されます。

このアプリケーションは、カテゴリ別および製品別の総売上を金額でソートして表示します。最もよく売れたカテゴリは "Beverages" であり、最もよく売れた製品は "Cote de Blaye" です。

ここで、上のグリッドにある列ヘッダー[ProductName]をクリックし、"Cote de Blaye" のエントリが見つかるまで下にスクロールします。見つかったら、いくつかの注文を変更して、サマリーデータが直ちに更新されることを確認します。たとえば、いくつかの "Cote de Blaye" 注文の数量をゼロに変更すると、"Beverages" が直ちに "Diary Products" カテゴリの後に移動します。

この単純な例は、LINQ ベースのライブビューの能力を示しています。LINQ ベースのライブビューは、データとロジックの橋渡しとなり、データ中心型アプリケーションを格段に簡潔かつ効率的に作成できるようにします。