DTOをWCF RIA Servicesで公開するには

http://weblogs.asp.net/fredriknormen/archive/2009/11/28/wcf-ria-services-and-a-guide-to-use-dto-presentation-model.aspx
上のサイトをみながら試行錯誤してみました。

Entity Frameworkを使うにしても使わないにしてもDTOに変換してクライアント側(Silverlight)に渡すのがシンプルで汎用的でまちがいがないと思いますね。DTOはこんな感じ。

    public class Employee
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

サービスはこんな感じ。DomainServiceを継承します。

    [EnableClientAccess()]
    public class MyDomainService : DomainService
    {
        public Employee GetEmployee()
        {
            return new Employee()
                   {
                       Id = 1,
                       Name = "Hoge",
                       Age = 30
                   };
        }
    }

これでビルドすると、クライアント側のSilverlightのプロジェクトにコードが自動生成されます。
ただ、DTOにはSystem.ComponentModel.DataAnnotations.KeyAttributeがないとコード生成が行われませんでした。KeyAttributeが必須なのかもしれない。それか、KeyAttributeでなくても別の方法で目印をつける方法があるのかも。


クライアント側では自動生成されたMyDomainContextを使ってこんな感じでサービスにアクセスできます。

    MyDomainContext context = new MyDomainContext();
    context.Load(_context.GetEmployeeQuery(), (op) =>
                                         {
                                             if (!op.HasError)
                                             {
                                                 Employee = op.Entities.First();
                                                 
                                             }
                                         }, null);

サーバー側のGetEmployeeに対応するメソッドの名前がGetEmployeeQueryになっています。あんまり理解できてませんが、とりあえず取得できました。


ところで、DTOのプロパティをTwoWayでバインディングして値を変更するとEditできないといった例外が発生しました。

System.NotSupportedException was unhandled by user code
  Message=This EntitySet of type 'BASample.Web.Models.Employee' does not support the 'Edit' operation.
  StackTrace:
       場所 System.ServiceModel.DomainServices.Client.EntitySet.EnsureEditable(EntitySetOperations operation)
       場所 System.ServiceModel.DomainServices.Client.Entity.RaiseDataMemberChanging(String propertyName)
       場所 BASample.Web.Models.Employee.set_Name(String value)
  InnerException: 

空のUpdateメソッドを追加したら解決(UpdateAttributeもありますが指定しなくても規約で判定してくれる?)。サーバーサイドで変更するしないに関係なくDTOを変更できていい気がしますが。

    [EnableClientAccess()]
    public class MyDomainService : DomainService
    {
        public Employee GetEmployee()
        {
            return new Employee()
                   {
                       Id = 1,
                       Name = "Hoge",
                       Age = 30
                   };
        }

        public void UpdateEmployee(Employee employee)
        {            
        }
    }