检索自定义实体的CRM 4 C# [英] Retrieving custom entities in CRM 4 C#

查看:246
本文介绍了检索自定义实体的CRM 4 C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们的CRM环境中的用户具有的1:N关系到其表示其实际可用小时的一周的可用时间实体。我正在寻找在C#的方式来获取所有可用小时是一个特定的团队,为本周的用户。



我是新来的CRM开发和我环顾四周,但似乎有很多方法可以做到这一点,林不知道这是最适合的。



语言是C#和CRM的版本是MS CRM 4.0


解决方案

我将介绍这3位:上的代码一般方法,代码本身然后一些注意事项(代码注释提请注意某些事情,虽然但其中一些将承担代码之外进一步解释)。



常规方法



如您所见,有一对夫妇的方式做事情,但外部应用程序通过它归结为3个主要选择网络服务与CRM进行交互:




  1. 使用强类型的方法,你从添加Web引用在Web服务调用来检索您的自定义实体(我想你在前面的问题中提到的看方法的爆炸......当你有很多自定义实体的这种恶化)

  2. 使用 DynamicEntity 在您的Web服务调用

  3. FetchXML



如果你的系统是超级简单,你通常可以逃脱(1),但我会建议,要么(2)或(3)。利用式(2)意味着你只有真正要记住的Web服务方法屈指可数其良好的如果你曾经进入插件或工作流组件的概念横跨携带还算不错。如果你知道FetchXML并能形成相应的查询(3)是不错的。



我通常使用(2)它是常见的,它是一个很好的中间处理这些事道路的做法,就像我说的,你的代码将是相当容易转化为一个插件或工作流组件。 FetchXML进行跨得很好,但我从来没有善于形成的疑问 - 我会支付稍后一些技术,但让去(2)



另外,如果。您使用 DynamicEntity 你不应该需要刷新,因为你如何与它和它的属性对象(基本上你得到强类型的牺牲灵活性),你会在代码中看到。如果你有去(1)你强类型对你的自定义实体,但你必须保持你的清爽根据Web引用上的变化人们对您的实体的节奏。



< H2>代码

这是在我添加了一个Web引用到CRM服务,并做了一些电话,模拟您的方案有点控制台应用程序。该代码应携带跨越到其他应用程序,如Web应用程序。我试图评论它,所以它可能是值得一通过移动到下一个章节前仔细阅读。



NB。我不知道声称这是世界上最好的代码,但它似乎工作,应该让你开始)



NB2。我做打电话的错误我的命名空间Web引用 CrmService - 请不要犯同样的错误,因为我....)

 静态无效的主要(字串[] args)
{
CrmService.CrmService SVC =新CrmService.CrmService();
svc.CrmAuthenticationTokenValue =为gettoken();
svc.UseDefaultCredentials = TRUE;

#地区1 - 检索团队
RetrieveMembersTeamRequest teamMembersReq用户=新RetrieveMembersTeamRequest()
{
ENTITYID =新的GUID(D56E0E83-2198-E211-9900- 080027BBBE99),//你需要团队GUID
ReturnDynamicEntities = TRUE
};

ColumnSet teamMembersReqColumnSet =新ColumnSet();
teamMembersReqColumnSet.Attributes =新的字符串[] {systemuserid,域名};

teamMembersReq.MemberColumnSet = teamMembersReqColumnSet; //不要使用:teamMembersReq.MemberColumnSet =新AllColumns()

名单,LT;&的Guid GT; userIdList =新的List<&的Guid GT;();
RetrieveMembersTeamResponse teamMembersResp = svc.Execute(teamMembersReq)为RetrieveMembersTeamResponse;
如果(teamMembersResp!= NULL)
{
的BusinessEntity [] = usersInTeamAsBusinessEntity teamMembersResp.BusinessEntityCollection.BusinessEntities;
名单,LT; DynamicEntity> usersInTeamAsDynEntity = usersInTeamAsBusinessEntity.Select(是= GT;作为DynamicEntity).ToList(); //的BusinessEntity没有太大的用处,转换为DynamicEntity

的foreach(DynamicEntity在usersInTeamAsDynEntity日)
{
房产userIdProp = de.Properties.Where(P => p.Name ==systemuserid)FirstOrDefault();
房产domainNameProp = de.Properties.Where(P => p.Name ==域名)FirstOrDefault()。

如果(userIdProp!= NULL)
{
KeyProperty userIdKeyProp = userIdProp为KeyProperty; //因为它是实体
userIdList.Add(userIdKeyProp.Value.Value)的唯一标识符; //夹头中使用的列表后
Console.Write(键:+ userIdKeyProp.Value.Value.ToString());
}

如果(domainNameProp!= NULL)
{
StringProperty domainNameStringProp = domainNameProp为StringProperty; //因为它的数据类型为varchar
Console.Write(|域名:+ domainNameStringProp.Value);
}

Console.WriteLine();
}
}
#endregion

/ *
*在这个例子中我创建了一个虚拟实体,称为new_availablehours即以1:N的关系与使用(即1用户,许多new_available小时)。
*测试的属性是:
* - 关系属性称为new_userid ......这显然对面的GUID从systemuser
*链接 - 有一个叫做new_hours $ int数据类型属性b $ b * - 有一个名为new_availabilityday
* /
#地区检索1 datetime属性:N
RetrieveMultipleRequest REQ =新RetrieveMultipleRequest();
req.ReturnDynamicEntities = TRUE; //因为我们爱DynamicEntity

// QueryExpression说,从检索的实体,我们想要的东西列回来,我们用什么准则来选择
QueryExpression QE =新QueryExpression();
qe.EntityName =new_availablehours; //对1的很多副作用实体:我们想从

qe.ColumnSet =新AllColumns数据()N; //不要在现实生活中做到这一点,限制它就像我们检索团队成员时,

/ *
*在这种情况下,确实我们有将多个条件运算符$ 1个过滤器表达式b $ b *条件运营商一起评估使用FilterExpression对象的FilterOperator财产(这是AND或OR)
*
*所以,如果我们使用和所有条件必须是真实的,如果我们使用或再提供需要的条件的至少一个为真
*的
*表/
FilterExpression FE =新FilterExpression();
fe.FilterOperator = LogicalOperator.And;

ConditionExpression userCondition =新ConditionExpression();
userCondition.AttributeName =new_userid; //这是我们要测试的反对
userCondition.Operator = ConditionOperator.In qe.EntityName的属性; //因为我们得到了用户的列表以前,适当的检查得到的记录,其中new_userid在我们前面产生
userCondition.Values = userIdList.Select(S = GT有效的人的名单; s.ToString( ))ToArray的()。 //翻转GUID对字符串(似乎CRM喜欢的),然后将它们作为我们想evaulate
// OK的价值观 - 所以现在我们有这个userCondition,其中有效记录ID的集合中有其new_userid价值我们指定

ConditionExpression dateWeekBound =新ConditionExpression();
dateWeekBound.AttributeName =new_availabilityday;
dateWeekBound.Operator = ConditionOperator.ThisWeek; // ConditionOperator有一大堆方便运营商(如本周最后X天等)来处理日期 - 检查出来,因为他们是非常方便的

/ *
*作为不谈,如果我们不希望使用的便利性操作符(或者如果没有可用),我们将不得不建立一个类似ConditionExpression:
*
* ConditionExpression dateLowerBound =新ConditionExpression();
*的dateLowerBound.AttributeName =new_availabilityday;
* dateLowerBound.Operator = ConditionOperator.OnOrAfter;
* dateLowerBound.Values =新对象[] {<您的DateTime对象这里> };
*的
*和对应的一个用于上界使用ConditionOperator.OnOrBefore
*的
*的另一种替代方法是使用ConditionOperator.Between。这是灵活任何类型的数据,但值数组的格式将是这样的:
* ce.Values =新对象[] {<下界>中,<上限> };
* /

fe.Conditions =新ConditionExpression [] {userCondition,dateWeekBound}; //添加条件到过滤
qe.Criteria =菲; //告诉查询正是我们过滤器是
req.Query = QE; //告诉要求,我们要使用

RetrieveMultipleResponse RESP = svc.Execute(REQ)作为RetrieveMultipleResponse查询;
如果(RESP!= NULL)
{
的BusinessEntity [] = rawResults resp.BusinessEntityCollection.BusinessEntities;
名单,LT; DynamicEntity> castedResults = rawResults.Select(R => R为DynamicEntity).ToList();

的foreach(DynamicEntity结果castedResults)
{
房产USER = result.Properties.Where(P => p.Name ==new_userid)。FirstOrDefault() ;
房产小时= result.Properties.Where(P => p.Name ==new_hours)。FirstOrDefault();

如果(用户!= NULL)
{
LookupProperty relationshipProperty =用户为LookupProperty; //重要 - 的关系属性强制转换为LookupProperty
Console.Write(relationshipProperty.Value.Value.ToString()+);
}

如果(小时!= NULL)
{
CrmNumberProperty hoursAsCrmNumber =小时,CrmNumberProperty; //我们也有CrmFloatProperty,CrmDecimalProperty等:如果属性的数据类型
Console.Write(hoursAsCrmNumber.Value.Value)的;
}

Console.WriteLine();
}
}
#endregion

到Console.ReadLine();
}

静态CrmAuthenticationToken为gettoken()
{
CrmAuthenticationToken令牌=新CrmAuthenticationToken();
token.AuthenticationType = 0; // Active Directory的
token.OrganizationName =DevCRM;

返回令牌;
}



So..What是什么?



我不打算做一个窜吹,但家中的关键点:




  1. 使用该服务时的主要​​手段是我们传递一个请求对象,并取回响应对象的执行()方法。这些要求都将是类的对象<动作>请求和响应将是类的对象<动作>响应

  2. 您通常需要使用 DynamicEntity 来工作 - <动作>请求对象通常公开一个名为 ReturnDynamicEntities 属性,你应该设置为真正

  3. <动作>请求对象有一个 ColumnSet 属性,你可以指定你想要什么属性回。它通常是不好的做法,指定 AllColumns(),而是你应该更明确一些希望返回的数据你。属性需要他们的名字相匹配的CRM(这样形式的<前缀GT; _<现场名称> ),并在所有的小写

  4. 让用户在一个团队中,因为它是在CRM并​​没有什么特别之处一个预定义的操作......在这种情况下的 SDK 是你的朋友,因为它会告诉你这些工作

  5. 检索一堆自定义实体是怎样一个更有趣的用例,我们通常可以得到这些出使用 RetrieveMultipleRequest RetrieveMultipleResponse 方法(如果你只想要一个记录那么你可以使用 RetrieveRequest RetrieveResponse ...但你需要知道的GUID您正在寻找什么喂到 RetreiveRequest 对象)。

  6. 对于 RetrieveMultipleRequest 我们喂它查询( QueryExpression ),它说什么实体(实体名称),我们想要得到的多,属性( ColumnSet ),我们要返回实体,用来选择我们想要的实际记录的过滤器(标准)的

  7. 专注于 QueryExpression FilterExpression的使用 ConditionExpression 。要知道一个重要的事情是你必须为您提供哪些运营商在 ConditionExpression - 我曾尝试打电话给一些列的代码,但再次SDK是你最好的朋友知道什么是可用

  8. 的东西我还没有介绍像(X或Y)和Z更复杂的过滤。有一个相当不错的例子这里。这只是用不同的方式 FilterExpression ConditionExpression

  9. 注意 RetrieveMultipleResponse 包含的BusinessEntity 的数组。在的BusinessEntity 本身没什么用,所以我们投了以列表 DynamicEntity - LINQ真的是你的朋友在这里和对于相当多的与CRM的东西搞乱,LINQ就派上用场了

  10. 请注意我们如何检查的属性 - de.Properties.Where(p => p.Name ==systemuserid)FirstOrDefault(); ,然后检查它是否 NULL 。这是因为如果在CRM中记录的属性是 NULL 它不会从服务调用返回 - 这样只是因为你要求在<$ C $属性C> ColumnSet 不要让自动假设它是存在的(除非你有它设置在CRM作为强制性 - 那么很可能OK)...测试它和你的应用程序会少了一大堆脆

  11. 属性类本身价值有限 - 真正与属性工作,你必须将它转换为东西它实际上是。我一直在喋喋不休的关于它,但SDK会告诉你的类型是什么,但它开始了一段时间后感觉自然,例如备案GUID是在 KeyProperty ,int的数据是在 CrmNumberProperty ,彩车在 CrmFloatProperty ,字符串是 StringProperty 等。注意弱类型(我前面提到的),我们必须获得通过名称属性转换为适当的值等



其他小贴士




  1. 常你将必须与服务呼叫相当健谈 - 从我见过的对CRM开发(我只能说说我自己的经历虽然)时,这是相当正常的

  2. 要在如何代码真的防守是很重要的 - 检查的属性存在,请检查您铸造到正确的类型等

  3. 如果你必须抓住一个例外,它会。是 的SoapException 以及您通常希望将在的 详细信息 财产 - 非常重要的,记住这一点,否则你会看到异常,并认为它不会告诉你一个一大堆

  4. 请回来在CRM中的自定义属性的关系搞清楚的名字,数据类型等。我喜欢有实体的自定义窗口,我需要开放的,而这样做的开发参考。

  5. FetchXML 真的很强大,但真的很繁琐。如果你善于它虽然那么你会得到很多很好的里程 - 就像一个工具是很有用的。此外,方便的技巧 - 如果你可以构造你想要什么(或者你想要的一个例子)作为一种先进的发现通过CRM用户界面,那么你可以用这个的诱骗得到它使用的FetchXML .. ..you'll可能需要调整的GUID之类的,但如果你想使用FetchXML在你的代码,因为大部分的查询是为你写它给你一个组成部分。

  6. 根据您的部署环境中,你可能要惹使用哪些凭据身边,无论你通过代理等......典型的web参考的东西。只是值得注意的是,CRM也不能幸免于这样的事 - 我没有任何实际的建议在这里,只是因为它已经引起了我一些有趣过去


  7. In our CRM environment users have a 1:N relation to an available hours entity which represents their actually available hours for the week. I'm looking for a way in c# to retrieve all the available hours for users that are of a specific team for the current week.

    I'm new to developing in CRM and I've looked around but there seems to be a lot of ways to do this and im not sure which is best suited.

    The language is C# and the version of CRM is MS CRM 4.0

    解决方案

    I'll cover this is 3 bits: general approach, code itself and then some notes on the code (the code is commented to draw attention to certain things, though but some of them will bear further explanation outside the code).

    General Approach

    As you've seen, there are a couple of ways to do things but for external applications interacting with CRM via the web service it comes down to 3 main options:

    1. Use the strongly typed methods you get from adding a web reference in web service calls to retrieve your custom entities (I think you mentioned in a previous question seeing an explosion of methods...this gets worse when you have a lot of custom entities)
    2. Use DynamicEntity in your web service calls
    3. FetchXML

    If your system is super-simple you can normally get away with (1) but I would recommend either of (2) or (3). Using (2) means that you only really have to remember a handful of web service methods and its good if you ever move into plugins or workflow assemblies as the concepts carry across reasonably well. (3) is good if you know FetchXML and can form the appropriate query.

    I normally approach these things using (2) as it's commonly found, it's a nice middle of the road approach and, like I said, your code will be reasonably easy to translate to a plugin or workflow assembly. FetchXML carries across quite well but I was never good at forming the queries - I'll cover some techniques for this later but lets go with (2).

    Also, if you use DynamicEntity you shouldn't need to refresh your web references because of how you work with it and its array of Property objects (basically you get flexibility at the expense of strong typing) as you'll see in the code. If you go with (1) you get strong typing against your custom entities but you'll have to keep refreshing your WebReference depending on the cadence of changes people make to your entities.

    The Code

    This is in a little console application where I've added a WebReference to the CRM service and done some calls to simulate your scenario. The code should carry across to other apps like web apps. I have tried to comment it so it is probably worth a read through before moving to the next section.

    (NB. I don't claim this is the world's best code, but it does seem work and should get you started)

    (NB2. I made the mistake of calling my namespace for the web reference CrmService - please don't make the same mistake as me....)

    static void Main(string[] args)
    {
            CrmService.CrmService svc = new CrmService.CrmService();
            svc.CrmAuthenticationTokenValue = GetToken();
            svc.UseDefaultCredentials = true;
    
            #region 1 - Retrieve users in team
            RetrieveMembersTeamRequest teamMembersReq = new RetrieveMembersTeamRequest()
            {
                EntityId = new Guid("D56E0E83-2198-E211-9900-080027BBBE99"), //You'll need the team GUID
                ReturnDynamicEntities = true
            };
    
            ColumnSet teamMembersReqColumnSet = new ColumnSet();
            teamMembersReqColumnSet.Attributes = new string[] { "systemuserid", "domainname" };
    
            teamMembersReq.MemberColumnSet = teamMembersReqColumnSet; //Don't use: teamMembersReq.MemberColumnSet = new AllColumns()
    
            List<Guid> userIdList = new List<Guid>();
            RetrieveMembersTeamResponse teamMembersResp = svc.Execute(teamMembersReq) as RetrieveMembersTeamResponse;
            if (teamMembersResp != null)
            {
                BusinessEntity[] usersInTeamAsBusinessEntity = teamMembersResp.BusinessEntityCollection.BusinessEntities;
                List<DynamicEntity> usersInTeamAsDynEntity = usersInTeamAsBusinessEntity.Select(be => be as DynamicEntity).ToList(); //BusinessEntity not too useful, cast to DynamicEntity
    
                foreach (DynamicEntity de in usersInTeamAsDynEntity)
                {
                    Property userIdProp = de.Properties.Where(p => p.Name == "systemuserid").FirstOrDefault();
                    Property domainNameProp = de.Properties.Where(p => p.Name == "domainname").FirstOrDefault();
    
                    if (userIdProp != null)
                    {
                        KeyProperty userIdKeyProp = userIdProp as KeyProperty; //Because it is the unique identifier of the entity
                        userIdList.Add(userIdKeyProp.Value.Value); //Chuck in a list for use later
                        Console.Write("Key: " + userIdKeyProp.Value.Value.ToString());
                    }
    
                    if (domainNameProp != null)
                    {
                        StringProperty domainNameStringProp = domainNameProp as StringProperty; //Because its data type is varchar
                        Console.Write("| Domain Name: " + domainNameStringProp.Value);
                    }
    
                    Console.WriteLine();
                }
            }
            #endregion
    
            /*
             * For this example I have created a dummy entity called new_availablehours that is in a 1:N relationship with use (i.e. 1 user, many new_available hours). 
             * The test attributes are :
             *      - the relationship attribute is called new_userid...this obviously links across to the GUID from systemuser
             *      - there is an int data type attribute called new_hours
             *      - there is a datetime attribute called new_availabilityday
             */
            #region Retrieve From 1:N
            RetrieveMultipleRequest req = new RetrieveMultipleRequest();
            req.ReturnDynamicEntities = true; //Because we love DynamicEntity
    
            //QueryExpression says what entity to retrieve from, what columns we want back and what criteria we use for selection
            QueryExpression qe = new QueryExpression();
            qe.EntityName = "new_availablehours"; //the entity on the many side of the 1:N which we want to get data from
    
            qe.ColumnSet = new AllColumns(); //Don't do this in real life, limit it like we did when retrieving team members
    
            /*
             * In this case we have 1 x Filter Expression which combines multiple Condition Operators
             * Condition Operators are evaluated together using the FilterExpression object's FilterOperator property (which is either AND or OR)
             * 
             * So if we use AND all conditions need to be true and if we use OR then at least one of the conditions provided needs to be true
             * 
             */
            FilterExpression fe = new FilterExpression();
            fe.FilterOperator = LogicalOperator.And;
    
            ConditionExpression userCondition = new ConditionExpression();
            userCondition.AttributeName = "new_userid"; //The attribute of qe.EntityName which we want to test against
            userCondition.Operator = ConditionOperator.In; //Because we got a list of users previously, the appropriate check is to get records where new_userid is in the list of valid ones we generated earlier
            userCondition.Values = userIdList.Select(s => s.ToString()).ToArray(); //Flip the GUID's to strings (seems that CRM likes that) then set them as the values we want to evaulate
            //OK - so now we have this userCondition where valid records have their new_userid value in a collection of ID's we specify
    
            ConditionExpression dateWeekBound = new ConditionExpression();
            dateWeekBound.AttributeName = "new_availabilityday";
            dateWeekBound.Operator = ConditionOperator.ThisWeek; //ConditionOperator has a whole bunch of convenience operators to deal with dates (e.g. this week, last X days etc) - check them out as they are very handy
    
            /*
             * As an aside, if we didn't want to use the convenience operator (or if none was available) we would have to create a ConditionExpression like:
             * 
             * ConditionExpression dateLowerBound = new ConditionExpression();
             * dateLowerBound.AttributeName = "new_availabilityday";
             * dateLowerBound.Operator = ConditionOperator.OnOrAfter;
             * dateLowerBound.Values = new object[] { <Your DateTime object here> };
             * 
             * And a corresponding one for the upper bound using ConditionOperator.OnOrBefore
             * 
             * Another alternative is to use ConditionOperator.Between. This is flexible for any sort of data, but the format of the Values array will be something like:
             *      ce.Values = new object[] { <lower bound>, <upper bound> };
             */
    
            fe.Conditions = new ConditionExpression[] { userCondition, dateWeekBound }; //Add the conditions to the filter
            qe.Criteria = fe; //Tell the query what our filters are
            req.Query = qe; //Tell the request the query we want to use
    
            RetrieveMultipleResponse resp = svc.Execute(req) as RetrieveMultipleResponse;
            if (resp != null)
            {
                BusinessEntity[] rawResults = resp.BusinessEntityCollection.BusinessEntities;
                List<DynamicEntity> castedResults = rawResults.Select(r => r as DynamicEntity).ToList();
    
                foreach (DynamicEntity result in castedResults)
                {
                    Property user = result.Properties.Where(p => p.Name == "new_userid").FirstOrDefault();
                    Property hours = result.Properties.Where(p => p.Name == "new_hours").FirstOrDefault();
    
                    if (user != null)
                    {
                        LookupProperty relationshipProperty = user as LookupProperty; //Important - the relationship attribute casts to a LookupProperty
                        Console.Write(relationshipProperty.Value.Value.ToString() + ", ");
                    }
    
                    if (hours != null)
                    {
                        CrmNumberProperty hoursAsCrmNumber = hours as CrmNumberProperty; //We also have CrmFloatProperty, CrmDecimalProperty etc if the attribute was of those data types
                        Console.Write(hoursAsCrmNumber.Value.Value);
                    }
    
                    Console.WriteLine();
                }
            }
            #endregion
    
            Console.ReadLine();
        }
    
        static CrmAuthenticationToken GetToken()
        {
            CrmAuthenticationToken token = new CrmAuthenticationToken();
            token.AuthenticationType = 0; //Active Directory
            token.OrganizationName = "DevCRM";
    
            return token;
        }
    

    So..What Was That?

    I'm not going to do a blow-by-blow, but home in on the key points:

    1. The key method when using the service is the Execute() method where we pass it a request object and get back a response object. The requests will all be objects of class <Operation>Request and responses will be objects of class <Operation>Response.
    2. You typically want to work with DynamicEntity - the <Operation>Request objects will typically expose a property called ReturnDynamicEntities which you should be setting to true
    3. Most <Operation>Request objects have a ColumnSet property where you can specify what attributes you want returned. It is typically bad practice to specify AllColumns() and instead you should be explicit about what data you want returned. Attributes need to match their names in CRM (so of the form <prefix>_<field name>) and all in lower case
    4. Getting users in a team isn't too interesting as it's a predefined operation in CRM and nothing special...in this case the SDK is your friend as it'll show you how these work
    5. Retrieving a bunch custom entities is a more interesting use case and we can normally get these out by using the RetrieveMultipleRequest and RetrieveMultipleResponse methods (if you only want one record then you can just use RetrieveRequest and RetrieveResponse...but you need to know the GUID of what you are looking for to feed into the RetreiveRequest object).
    6. For RetrieveMultipleRequest we feed it a query (QueryExpression) which says what entity(EntityName) we want to get multiple of, the attributes(ColumnSet) of that entity we want to return and the filter(Criteria) which is used to select the actual records we want
    7. Focus on the usage of QueryExpression, FilterExpression and ConditionExpression. An important thing to know is what operators you have available for you in ConditionExpression - I have tried to call some out in the code, but once again the SDK is your best friend to know what is available
    8. Something I haven't covered is more complex filtering like (x OR y) AND z. There is a reasonably good example here. It's just a different way to use FilterExpression and ConditionExpression
    9. Note that RetrieveMultipleResponse contains an array of BusinessEntity. The BusinessEntity by itself is pretty useless so we cast that to a list of DynamicEntity - LINQ is really your friend here and for quite a bit of messing with CRM stuff, LINQ comes in handy
    10. Note how we check properties - de.Properties.Where(p => p.Name == "systemuserid").FirstOrDefault(); and then check if it is NULL. This is because if in CRM an attribute of a record is NULL it won't be returned from the service call - so just because you request an attribute in the ColumnSet don't make the automatic assumption it is there (unless you have it set as mandatory in CRM - then probably OK)...test it and your app will be a whole lot less brittle.
    11. The Property class itself has limited value - to really work with a property you have to cast it to the thing it actually is. I keep harping on about it but the SDK will tell you what the types are but it starts to feel natural after a while, e.g. the GUID for the record is in a KeyProperty, ints are in CrmNumberProperty, floats are in CrmFloatProperty, strings are StringProperty etc. Note the weak typing (which I mentioned previously) where we have to get properties by name, cast to the proper value etc

    Other Takeaways

    1. Normally you're going to have to be quite chatty with the service calls - from what I've seen this is fairly normal when developing against CRM (I can only talk about my own experience though)
    2. It is important to be really defensive in how you code - check that properties exist, check you're casting to the right types etc.
    3. If you have to catch an exception it'll be a SoapException and the info you typically want will be in the Detail property - very important to remember this or you'll look at the exception and think it's not telling you a whole bunch
    4. Consult back with the customizations in CRM to figure out the name of relationship attributes, data types etc. I like to have the customizations window for the entities I need open while doing dev for easy reference.
    5. FetchXML is really powerful but really fiddly. If you get good at it though then you'll get a lot of good mileage - a tool like this is useful. Also, a handy trick - if you can construct what you want (or an example of what you want) as an advanced find through the CRM UI then you can use this trick to get the FetchXML it used....you'll probably need to tweak the GUIDs and the like but it gives you a building block if you want to use FetchXML in your code as most of the query is written for you.
    6. Depending on your deployment environment, you might have to mess around with what credentials are used, whether you go through a proxy etc...typical web reference stuff. Just worth noting that CRM isn't immune to that kind of thing - I don't have any real advice here, just a note as it has caused me some "fun" in the past

    这篇关于检索自定义实体的CRM 4 C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆