crmsvcutil を使用して事前バインドされたエンティティクラスを生成する方法を[Dynamics CRM 2011]crmsvcutil.exe を使用した事前バインドクラスの生成 で記載しました。今回はプロキシクラスを使用してエンティティのレコードを操作するサンプルを記載します。

動作環境は次の通りです

  • Windows Server 2008 R2 上に構築した Dynamics CRM 2011 UR 5 オールインワン環境
  • Visual Studio 2010 Professional SP1

1. プロキシクラスの生成

crmsvcutil ツールを使用してエンティティのプロキシクラスとサービスコンテキストクラスを作成します。以下はOnPremise 上でのコマンドサンプルです。

crmsvcutil /url:http://crmsvr01/org01/XRMServices/2011/Organization.svc /out:XrmProxy.cs /namespace:Handcraft.Xrm.Client /servicecontextname:XrmContext


2. サンプルプログラムの作成

Visual Studio 2010 を起動して、コンソールプロジェクトを作成します。

2.1 参照の設定

生成したクラスファイルをプロジェクトに追加します。ソリューションエクスプローラ上で、プロジェクトを右クリック→追加→既存の項目で作成した XrmProxy.cs をプロジェクトに追加します。

次に、必要なdll参照の追加と、ターゲットのフレームワークを変更します。プロジェクトのプロパティ画面を表示し、 対象のフレームワークを .NET Framework 4.0 にします(Client Profileではないので注意)。 参照の追加で、次のdllへの参照を追加します。System.ServiceModel.dll,System.Runtime.Serialization.dll,microsoft.xrm.sdk.dll,microsoft.crm.sdk.proxy.dll

2.2 サンプルプログラム

CRUD操作や、関連の設定、レコードの非アクティブ化を行うサンプルプログラムを以下に記載します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using System.ServiceModel;

namespace EarlyBindingSample02
{
    // 自動生成したプロキシクラスのネームスペース
    using Handcraft.Xrm.Client;

    class Program
    {
        /// <summary>
        /// Early-Bound なエンティティクラスを使用して
        /// レコードのCRUDを行うサンプルプログラムです。
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            using (OrganizationServiceProxy proxy = GetOrganizationService("crmsvr01", "org01"))
            {
                try
                {
                    proxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
                    EarlyBoundCRUD(proxy);
                }
                catch (TimeoutException)
                {
                }
                catch (FaultException<OrganizationServiceFault>)
                {
                }
                catch (FaultException)
                {
                }
                catch (Exception)
                {
                }
            }
        }

        /// <summary>
        /// Early-Bound なエンティティクラスを使用する場合のCRUDサンプル
        /// N:Nの場合はIOrganizationService.Associate, Disassociate 
        /// および AssociateRequest, DIsassociateRequest を使用する
        /// </summary>
        /// <param name="proxy"></param>
        public static void EarlyBoundCRUD(OrganizationServiceProxy proxy)
        {
            XrmContext context = new XrmContext(proxy);

            // Create
            Contact contact = new Contact()
            {
                FirstName = "First",
                LastName = "Last",
                YomiFirstName = "ヨミメイ",
                YomiLastName = "ヨミセイ"
            };


            context.AddObject(contact);
            context.AddObject(new Contact());
            context.SaveChanges();
            // もし、Early Bounnd なプロキシエンティティを使用してかつ、ProxyTypesBehavior を
            // OrganizationServiceProxyのエンドポイントに設定しないで、OrganizationServiceProxy
            // のメソッドとプロキシクラスを組み合わせて使用する場合、事前にEnableProxyTypes 
            // メソッドの呼び出しが必要です。
            //proxy.EnableProxyTypes();
            //proxy.Create(contact);

            // Update
            // 上で作成したContactをUpdateでも使用するためコンテキストにアタッチ
            context.Attach(contact); 
            contact.EMailAddress1 = "test@hello.jp";
            context.UpdateObject(contact);
            context.SaveChanges();

            // SetState
            SetStateRequest request = new SetStateRequest();
            request.EntityMoniker = new EntityReference(Contact.EntityLogicalName, contact.ContactId.Value);
            request.State = new OptionSetValue((int)ContactState.Inactive);
            request.Status = new OptionSetValue(-1);
            // Execute を使用するリクエストは Execute を使用する必要あり.割り当てAssignRequestも同様
            context.Execute(request); 

            // クエリ RetrieveMultiple,Retrieve
            var query = from c in context.CreateQuery<Contact>()
                        where c.FirstName == "First"
                        select c;
            // 1レコードのみ取得
            query.Take(1);

            Contact foundContact = null;
            foreach (var item in query)
            {
                Console.WriteLine(item.FirstName);
                Console.WriteLine(item.EMailAddress1);
                foundContact = item as Contact;
            }

            // Delete
            context.DeleteObject(foundContact);
            context.SaveChanges();

            // Associate (1:N)
            Account act = context.AccountSet.Where(x => x.Name == "企業2").Take(1).First();

            var query2 = context.ContactSet.Where(x => x.LastName.StartsWith("名"));
            EntityReferenceCollection cols = new EntityReferenceCollection();
            foreach (var item in query2)
            {
                // AddLink,DeleteLink, Associate,Disassociateを使用する方法もあるSDK参照
                cols.Add(new EntityReference(Contact.EntityLogicalName, item.ContactId.Value));
                item.ParentCustomerId = new EntityReference(Account.EntityLogicalName, act.AccountId.Value);
                // AddLink の場合. AddObject と AddLink を同時に行う場合は、AddRelatedObjectを使用できる
                //context.AddLink(item, new Relationship("contact_customer_accounts"), act);
                context.UpdateObject(item);
            }
            context.SaveChanges();

            // プロパティを遅延ロードするサンプル
            context.Attach(act);
            Console.WriteLine(act.contact_customer_accounts == null);
            context.LoadProperty(act, new Relationship("contact_customer_accounts"));
            Console.WriteLine(act.contact_customer_accounts.Count());
            // 関連の解除
            proxy.Disassociate(Account.EntityLogicalName, act.AccountId.Value, new Relationship("contact_customer_accounts"), cols);
        }
        /// <summary>     
        /// Crm On-Premise に接続する     
        /// </summary>     
        /// <param name="server">サーバー名</param>     
        /// <param name="orgname">組織名</param>     
        /// <returns>OrganizationServiceProxy のインスタンス</returns>     
        public static OrganizationServiceProxy GetOrganizationService(string server, string orgname)
        {
            string endpointaddress = string.Format("http://{0}/{1}/XRMServices/2011/Organization.svc", server, orgname);
            OrganizationServiceProxy organizationService = new OrganizationServiceProxy(new Uri(endpointaddress), null,
                new System.ServiceModel.Description.ClientCredentials(), null);

            return organizationService;
        }   
    }
}

 

3.まとめ

説明は以上です。事前バインドされたクラスを使用するとコンパイル時に属性の型や名前の誤りがわかるので便利です。ただし、事前バインディングで使用できる操作は基本的にCRUDメッセージ(組織サービスにおける xRM メッセージ)の処理だけです。CRM特有のメッセージ(組織サービスの CRM メッセージ)は Execute メソッドを使用する必要があります。