Silverlight で EF4 新機能 Self-Tracking Entities を活用


最近、忙しさにかまけて Blog を随分サボっていました。すみません。

書きたいことは山のようにあるのですが、、、

 

さて、今日は Entity Framework 4 の新機能 Self-Tracking Entities を Silverlight で利用してみましょう。Self-Tracking Entities をご存じない方は私の過去記事 ADO.NET Entity Framework を用いたN階層システムの構築手法 を参考にしてください。

 

今回作るモノ

DBの検索、更新処理を伴う Silverlight 4 アプリケーション

clip_image001

 

 

必要な環境

・Visual Studio 2010/.NET 4

SQL Server 2005/2008

Silverlight 4 tools

pubs サンプルデーターベース

 

実装

1. VS2010 で新規に Silverlight アプリケーションを作成します。(プロジェクト名は”Jobs”)

 

2. Silverlight クラスライブライ プロジェクトを追加します。(プロジェクト名は”JobsEntities”)

ここには後々、クライアントサイドで利用する Self-Tracking Entities 作成することになります。

clip_image002

 

次のようなソリューションになっているはずです。

クライアントサイドプロジェクト "jobs” に”jobsEntities” への参照を追加しておきましょう。

clip_image003

 

3. サーバーサイド(”jobs.Web”)を作成していきましょう。

    jobs.Web に Entity Data Model を追加します。今回はサンプル DB でお馴染みの pubs DB の “employee” と “jobs” テーブルを Entity として追加します。employee と jobs は次のように 1 : N の関連があります。ちなみに、ここでは EntityFramework の複数化機能は On にしておきました。あまり意味はありませんが・・・

また Self-Tracking Entities を作成するのでデフォルトで自動生成される Entity や Context は削除する必要があります。edmx ファイルのプロパティで ”カスタムツール” に設定されている ”EntityModelCodeGenerator” を削除しておきます。そしてデザイナのコンテキストメニューから “コード生成項目の追加” を選択します。

clip_image004

 

“ADO.NET Self-Tracking Entity ジェネレーター” を選択します。名前は”Model.tt” にしました。

clip_image005

 

すると、Model.Context.tt (Contextクラス)と Model.tt (Self-Tracking Entity クラス)が生成されましたね。

DBアクセスはこれでOKです。それではサービスを作成しましょう。

今回はクライアントが Silverlight アプリケーションなので “Silverlight 対応 WCF サービス を “jobs.Web”  プロジェクトに追加します。サービス名は “jobsService” にしました。

clip_image006

 

jobsService の実装はこんな感じです。

データの取得 “GetJobs” では Jobs データを全件取得します。加えてemployee も Incloude して取得します。データの更新 “UpdateJobs” ではApplyChanges を実行するだけで、jobs データのみならず、関連する employee データもまとめて 追加、更新、削除を実行してくる優れものです。以前は、追加、更新、削除でインタフェースを分けたりしていましたからね。実装が大変でした。

using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.ObjectModel;

namespace jobs.Web
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

    public class jobsService
    {
        [OperationContract]
        public ObservableCollection<job> GetJobs()
        {
            using (var ctx = new pubsEntities())
            {
                return new ObservableCollection<job>(
                                        ctx.jobs.Include("employees"));

            }
        }

        [OperationContract]
        public ObservableCollection<job> UpdateJobs(
                                        ObservableCollection<job> jobs)
        {
            using (var ctx = new pubsEntities())
            {
                foreach (var c in jobs)
                {
                    ctx.jobs.ApplyChanges(c);
                }
                ctx.SaveChanges();

            }

            return GetJobs();
        }
    }
}

 

ついでに WCF ではデフォルトで受信できるメッセージサイズが小さいので、少しサイズを大きくしておくとよいでしょう。 Web.config の maxReceivedMessageSize、maxBufferSize を次のように設定します。

<customBinding>

<binding name="jobs.Web.jobsService.customBinding0">

<binaryMessageEncoding />

<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"/>

</binding>

</customBinding>

 

4. 次はクライアントサイドです。

    jobsEntities プロジェクトに Self-Tracking Entities を追加します。既存の項目の追加で jobs.Web の Model.tt を選択します。 “リンクとして追加” することをお忘れなく。

clip_image007

 

また Entities はサーバーサイドと同じ名前空間に揃えておきたいので、jobsEntities プロジェクト既定の名前空間は “jobs.Web” に変更しておきましょう。こんな感じになりましたね。そうそう、当然 Entity はシリアライズ化してサービス経由でやりとりする DataContract になります。よって System.Runtime.Serialization を参照設定で追加しておく必要がありますね。

clip_image008

 

それでは jobs プロジェクトにサービス参照を追加します。名前空間は jobsServiceReference にしておきます。プロキシさえ出来てしまえばこっちのモノです。

clip_image009

 

データをバインドする画面の作り方はいろいろありますが、簡単なのはデータソースウィンドウからドラッグ&ドロップで画面を作成する方法でしょう。私はGUI ベースで次のようなレイアウトにしました。

clip_image010

 

job desc (コンボボックス)を選択すると関連する employee データ が DataGrid に表示されるようにしたいと思います。また Save ボタンを押すとデータ更新を実行します。

コードは以下の通りです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using jobs.jobsServiceReference;
using System.Collections.ObjectModel;
using jobs.Web;

namespace jobs
{
    public partial class MainPage : UserControl
    {

        ObservableCollection<job> _jobs;

        public MainPage()
        {
            InitializeComponent();

            jobsServiceClient service = new jobsServiceClient();
            service.GetJobsCompleted += (object s, GetJobsCompletedEventArgs args) => { SetJobs(args.Result); };
            service.GetJobsAsync();

        }

        private void SetJobs(ObservableCollection<job> newJobs)
        {
            _jobs = newJobs;
            job_descComboBox.DataContext = _jobs;
        }

        private void job_descComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            job j = (job)job_descComboBox.SelectedItem;
            employeesDataGrid.ItemsSource = j.employees;
        }

        private void SaveBtn_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                jobsServiceClient service = new jobsServiceClient();
                service.UpdateJobsCompleted += (object s,
                                           UpdateJobsCompletedEventArgs args) =>
                {
                    MessageBox.Show("The jobs saved successfully.");
                };

                service.UpdateJobsAsync(_jobs);
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("An error occured while saving the jobs:{0}{1}", Environment.NewLine, ex.Message));
            }
        }

    }
}

 

当然ながら Silverlight なので非同期を意識する必要はありますが、Self-Tracking Entities を利用すれば Change Tracking をご自身で実装する必要がなくなります。さらに同時実行制御や 1:N データをまとめて処理することも可能です。便利ですね~。

clip_image011


Comments (0)

Skip to main content