如何在初始化程序中设置对象实例并立即访问属性?

时间:2014-04-08 01:17:44

标签: c# dynamics-crm-2011

我正在反对.NET Framework中的特定SDK(CRM SDK,但对此问题并不重要;只是背景),它允许我针对数据存储库编写表达式并返回结果。这里的密钥是查询实际执行依赖于执行查询时我要求的字段。

因此,如果我运行一个包含6000个项目的表达式,则可能需要5分钟才能返回所有 120列和所有 6000 记录。但是,如果我只要求5-6个字段/列,则可能只需要5-10秒即可返回所有6000个项目。这里的关键关键是我在对象初始值设定项中要求的所有字段都会影响SDK运行的查询。

为此,我无法访问EntityReferenceobject initializer类型的媒体资源,并在1次通话中立即访问其中的媒体资源。一些代码要解释 - 下面有问题的代码。它也非常快因为执行的查询只要求3个属性,所以返回的数据很小:

var results = allAccountsQuery.Select(account => new Account
{
  AccountNo = account.GetAttributeValue<string>("AccountNumber"),
  //AccountID NOT working!
  AccountID = new EntityReference() { Id = account.GetAttributeValue<EntityReference>("AccountID").Id }.Id,
  Name = account.GetAttributeValue<string>("AccountName")
}).ToList();

违规行如下:

AccountID = new EntityReference() { Id = account.GetAttributeValue<EntityReference>("AccountID").Id }.Id

正如您所看到的,我尝试来实例化EntityReference的实例,对其进行初始化,然后立即在后端访问它的属性。它以Object reference not set to an instance of an object

失败

以下代码有效,但效率极低,因为它会带回所有内容。 SDK正在执行一些封面魔术,仅根据object initiazlizer中要求的字段评估查询。在这种情况下,查询正在进行评估,并且在循环的第一次迭代中,它会带回所有内容,但它可以工作:

List<Account> allAccounts = new List<Account>();
//Super slow - framework actually gets back ALL accounts in 1st iteration
foreach (var account in allAccountsQuery)
{
  Account newAccount = new Account
  {
     AccountNo = account.GetAttributeValue<string>("AccountNumber"),
     Name = account.GetAttributeValue<string>("AccountName")
  };

  //WORKS: This separate instantiation and then accessing of the property works!!
  //Note it is done in 2 steps outside the object initializer
  //Need to see if I can do this in an object initializer instead of separately
  EntityReference ef = account.GetAttributeValue<EntityReference>("AccountID");
  newAccount.AccountID = ef.Id;

  allAccounts.Add(newAccount);
}

所以问题是我如何在对象初始值设定项中指定EntityReference实例并提取它的属性Id,以便我得到的评估查询很小?

3 个答案:

答案 0 :(得分:0)

到目前为止,我发现最好的工作解决方案是将初始数据加载到匿名类型集合中,然后根据它加载实际的具体类型集合:

//Anonymous type collection
var accounts = allAccountsQuery.Select(account => new
{
  AccountNo = account.GetAttributeValue<string>("AccountNumber"),
  AccountID = account.GetAttributeValue<EntityReference>("AccountID"),
  Name = account.GetAttributeValue<string>("AccountName")
}).ToList();

现在我完成了定义EntityReference实例的脏工作,在填充具体类型时我可以访问它的.Id属性:

var results = accounts.Select(account => new Account
{
  AccountNo = account.AccountNo,
  AccountID = account.AccountID.Id,
  Name = account.Name
}).ToList();

这是经过测试和运作的。 results集合已定义了已实现的.Id属性。但是如你所见,我仍然需要分两步完成。但它解决了我的问题,因为查询运行得很快。我仍然愿意在1个对象初始化程序中执行此操作,因为如果我必须创建一种临时存储槽,然后才能访问并映射它,这个解决方案可能会变得很长。&#39 ; s属性以后。

我仍然更喜欢在单个对象初始值设定项中执行此加载的答案。

答案 1 :(得分:0)

如果我已正确理解您,您希望获得与以下SQL语句相当的请求

SELECT AccountNumber, Id, Name FROM Accounts

与CRM SDK的可比较请求将是

AccountSet.Select(account => new Account
{
  AccountNumber = account.AccountNumber,
  Id = account.Id,
  Name = account.Name
})

提示: ID或AccountId只是Guid EntityReference

因此,您对account.GetAttributeValue<EntityReference>("AccountID")的来电将返回null。因此,访问NullReference属性时会收到Id

这导致以下QueryExpression

<?xml version="1.0" encoding="utf-8"?>
<QueryExpression xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
  <ColumnSet>
    <AllColumns>false</AllColumns>
    <Columns xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
      <d3p1:string>accountnumber</d3p1:string>
      <d3p1:string>name</d3p1:string>
    </Columns>
  </ColumnSet>
  <Criteria>
    <Conditions />
    <FilterOperator>And</FilterOperator>
    <Filters />
  </Criteria>
  <Distinct>false</Distinct>
  <EntityName>account</EntityName>
  <LinkEntities />
  <Orders />
  <PageInfo>
    <Count>0</Count>
    <PageNumber>1</PageNumber>
    <PagingCookie i:nil="true" />
    <ReturnTotalRecordCount>false</ReturnTotalRecordCount>
  </PageInfo>
  <NoLock>false</NoLock>
</QueryExpression>

因此,只有这三个属性被请求并包含在结果中

答案 2 :(得分:0)

我不确定您的解决方案有什么问题,但我确定您确实希望限制查询表达式上的列,然后使用.ToEntity&lt;&gt;将您的集合转换为帐户的方法。

QueryExpression query = new QueryExpression("account");
query.ColumnSet = new ColumnSet(new string[] { "AccountId", "AccountNumber", "AccountName" });
List<Account> allAccounts = service.RetrieveMultiple(query).Entities.Select(account => account.ToEntity<Account>()).ToList<Account>();