前言
FetchXml 是一种基于 XML 的专有查询语言,用于从 Dataverse 检索数据。
添加引用
- Microsoft.CrmSdk.CoreAssemblies
- System.Configuration
检索数据(Retrieve data)
RetrieveMultiple
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Tooling.Connector;
using System;
using System.Configuration;
using System.Linq;
namespace FetchXml
{
internal class Program
{
static void Main(string[] args)
{
CrmServiceClient service = new CrmServiceClient(ConfigurationManager.ConnectionStrings["CRMConnString"].ConnectionString);
string fetchXml = @"<fetch top='5'><entity name='account'><attribute name='name' /></entity></fetch>";
EntityCollection entityCollection = RetrieveMultipleExample(service, fetchXml);
entityCollection.Entities.ToList().ForEach(e =>
{
Console.WriteLine($"Name:{e.GetAttributeValue<string>("name")}");
});
Console.WriteLine();
Console.ReadKey();
}
static EntityCollection RetrieveMultipleExample(IOrganizationService service, string fetchXml)
{
return service.RetrieveMultiple(new FetchExpression(fetchXml));
}
}
}
RetrieveMultipleRequest
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Tooling.Connector;
using System;
using System.Configuration;
using System.Linq;
using Microsoft.Xrm.Sdk.Messages;
namespace FetchXml
{
internal class Program
{
static void Main(string[] args)
{
CrmServiceClient service = new CrmServiceClient(ConfigurationManager.ConnectionStrings["CRMConnString"].ConnectionString);
string fetchXml = @"<fetch top='5'><entity name='account'><attribute name='name' /></entity></fetch>";
EntityCollection entityCollection1 = RetrieveMultipleRequestExample(service, fetchXml);
entityCollection1.Entities.ToList().ForEach(e =>
{
Console.WriteLine($"AccountName:{e.GetAttributeValue<string>("name")}");
});
Console.WriteLine();
Console.ReadKey();
}
static EntityCollection RetrieveMultipleRequestExample(IOrganizationService service, string fetchXml)
{
var request = new RetrieveMultipleRequest()
{
Query = new FetchExpression(fetchXml)
};
var response = (RetrieveMultipleResponse)service.Execute(request);
return response.EntityCollection;
}
}
}
选择列(Select columns)
attribute
当使用FetchXml查询数据时,通过使用entity
元素选择表来启动查询。
使用 attribute
选择要随查询返回的列。例如:
<fetch top='5'>
<entity name='account'>
<attribute name='accountclassificationcode' />
<attribute name='createdby' />
<attribute name='createdon' />
<attribute name='name' />
</entity>
</fetch>
string fetchXml = @"<fetch top='5'>
<entity name='account'>
<attribute name='accountclassificationcode' />
<attribute name='createdby' />
<attribute name='createdon' />
<attribute name='name' />
</entity>
</fetch>";
FetchExpression fetchExpression = new FetchExpression(fetchXml);
//Retrieve the data
EntityCollection entityCollection = service.RetrieveMultiple(query: fetchExpression);
此查询返回了Account表中前5行的accountclassificationcode
,createdby
,createdon
和name
列。此处使用了top限制了返回结果的大小。如果没有top限制,会默认返回前5000行数据
一般情况是不建议返回表中的所有列,返回所有列将使应用程序运行速度变慢,并可能导致超时错误。应该需要按照需要返回自己所需要的列。
all-attributes
使用all-attributes
元素可以返回表中所有列。
若在FetchXml中未指定列,也能返回所有列,但是并不建议这样做。
string fetchXml = @"<fetch top='5'>
<entity name='account'>
<all-attributes/>
</entity>
</fetch>";
//string fetchXml = @"<fetch top='5'>
//<entity name='account'>
//</entity>
//</fetch>";
FetchExpression fetchExpression = new FetchExpression(fetchXml);
//Retrieve the data
EntityCollection entityCollection = service.RetrieveMultiple(query: fetchExpression);
column aliases
使用 attribute
alias
属性为返回的结果指定唯一的列名。
返回的每一列都必须具有唯一的名称。默认情况下,为查询的表返回的列名是列LogicalName
值。每个表的所有列逻辑名称都是唯一的,因此该集合中不能有任何重复的名称。
使用 link-entity 元素联接表时,默认列名遵循以下命名约定:{Linked table LogicalName}.{Column LogicalName}
。这样可以防止任何重复的列名。您可以使用唯一的别名来覆盖此项。您还可以为表示联接表设置一个值。
string fetchXml = @"<fetch top='3'>
<entity name='account'>
<attribute name='accountclassificationcode' alias='code' />
<attribute name='createdby' alias='whocreated' />
<attribute name='createdon' alias='whencreated' />
<attribute name='name' alias='companyname' />
</entity>
</fetch>";
FetchExpression fetchExpression = new FetchExpression(fetchXml);
//Retrieve the data
EntityCollection entityCollection = service.RetrieveMultiple(query: fetchExpression);
foreach (var entity in entityCollection.Entities)
{
var code = ((OptionSetValue)entity.GetAttributeValue<AliasedValue>("code").Value).Value;
var whocreated = ((EntityReference)entity.GetAttributeValue<AliasedValue>("whocreated").Value).Name;
var whencreated = entity.GetAttributeValue<AliasedValue>("whencreated").Value;
var companyname = entity.GetAttributeValue<AliasedValue>("companyname").Value;
Console.WriteLine($"code:{code},whocreated:{whocreated},whencreated:{whencreated},companyname:{companyname}");
}
联接表(Join tables)
link-entity element
Many-to-one relationship
此查询根据客户记录中的 PrimaryContactId 查找列从客户和联系人表返回数据:
<fetch>
<entity name='account'>
<attribute name='name' />
<link-entity name='contact' from='contactid' to='primarycontactid' link-type='inner' alias='contact'>
<attribute name='fullname' />
</link-entity>
</entity>
</fetch>
One-to-many relationship
此查询基于联系人account_primary_contact一对多关系从联系人和客户表中返回数据。
<fetch>
<entity name='contact'>
<attribute name='fullname' />
<link-entity name='account' from='primarycontactid' to='contactid' alias='account'>
<attribute name='name' />
</link-entity>
</entity>
</fetch>
Many-to-many relationship
此查询使用teammembership_association多对多关系从 SystemUser 和 Team 表返回数据。
<fetch>
<entity name='systemuser'>
<attribute name='fullname' />
<link-entity name='teammembership' from='systemuserid' to='systemuserid' >
<link-entity name='team' from='teamid' to='teamid' link-type='inner' alias='team'>
<attribute name='name' />
</link-entity>
</link-entity>
</entity>
</fetch>
No relationship
可以使用不属于已定义关系的列来指定from和to属性。
例如,此查询查找记录对,其中客户记录的“名称”列与联系人记录的“完整名称”列匹配,而不管它们是否在任何查找列中相互引用。
<fetch>
<entity name='account'>
<attribute name='name' />
<link-entity name='contact' from='fullname' to='name' link-type='inner' alias='contact'>
<attribute name='fullname' />
</link-entity>
</entity>
</fetch>
重要的是,在from和to属性中指定的列是相同的类型,即使它们不涉及关系。使用不同类型的列将需要类型转换,这可能会对性能产生影响,并且可能会对某些列值失败。
以下列类型不能在from和to属性中使用:
- File
- Image
- MultiSelect Field
- PartyList
某些列可以在from和to属性中使用,但可能会导致较差的性能:
- 多行文本类型的列
- 最大长度大于850的单行文本类型的列
- 公式列
- 计算列
- 逻辑列
Attributes
名字 | 必填? | 描述 |
---|---|---|
name | 是 | 相关表的逻辑名称。 |
to | 否 | 父元素中要与from属性中指定的相关表列匹配的列的逻辑名称。 |
from | 否 | 与to属性中指定的列匹配的相关表中的列的逻辑名称。 |
alias | 否 | 表示相关表的名称。如果不设置别名,将为您生成一个别名,以确保所有列都具有唯一的名称,但您将无法使用该别名来引用fetch XML的其他部分中的链接实体。自动生成的别名使用模式{LogicalName}+{N},其中N是从1开始的获取XML中链接实体的序列号。 |
link-type | 否 | 链接使用的类型。默认行为是 inner. |
intersect | 否 | 指示链接实体用于联接表而不返回任何列,通常用于多对多关系。此属性的存在不会更改查询的执行。在联接表时,可以将此属性添加到链接实体中,但不包含任何属性元素以表明这是有意的。 |
link-type options
使用link-type
对返回的记录应用筛选器。下表介绍了有效的link-type
值:
Name | Description |
---|---|
inner | 默认,将结果限制为两个表中具有匹配值的行。 |
outer | 包括父元素中没有匹配值的结果。 |
any | 在 filter element中使用此功能。将结果限制为在链接实体中具有任何匹配行的父行。 |
not any | 在 filter element中使用此功能。将结果限制为链接实体中没有匹配行的父行。 |
all | 在 filter element中使用此功能。将结果限制为父行,其中链接实体中存在与from列值匹配的行,但这些匹配行都不满足为此链接实体定义的其他筛选器。您需要反转额外的过滤器,以找到每个匹配链接实体行都满足某些额外条件的父行。 |
not all | 在 filter element中使用此功能。将结果限制为链接实体中具有任何匹配行的父行。无论名称如何,此链接类型都等效于任何链接类型。 |
exists | inner 的一种变形,可以提升性能。在where子句中使用EXISTS条件。当结果中不需要父行的多个副本时,请使用此选项。 |
in | inner 的一种变形,可以提升性能。在where子句中使用IN条件。当结果中不需要父行的多个副本时,请使用此选项。 |
matchfirstrowusingcrossapply | inner 的一种变形,可以提升性能。当链接实体中只有一个匹配行的示例就足够了,并且不需要结果中父行的多个副本时,请使用此类型。 |
exists
FetchXml
<fetch>
<entity name='contact'>
<attribute name='fullname' />
<link-entity name='account' from='primarycontactid' to='contactid' link-type='exists'>
<filter type='and'>
<condition attribute='statecode' operator='eq' value='1' />
</filter>
</link-entity>
</entity>
</fetch>
SQL
select
"contact0".fullname as "fullname"
from Contact as "contact0"
where exists (
select "account1".primarycontactid
from Account as "account1"
where "account1".statecode = 1
and "contact0".contactid = "account1".primarycontactid)
in
FetchXml
<fetch>
<entity name='contact'>
<attribute name='fullname' />
<link-entity name='account' from='primarycontactid' to='contactid' link-type='in'>
<filter type='and'>
<condition attribute='statecode' operator='eq' value='1' />
</filter>
</link-entity>
</entity>
</fetch>
SQL
select
"contact0".fullname as "fullname"
from Contact as "contact0"
where "contact0".contactid in (
select "account1".primarycontactid
from Account as "account1"
where "account1".statecode = 1)
matchfirstrowusingcrossapply
FetchXml
<fetch>
<entity name='contact'>
<attribute name='fullname' />
<link-entity name='account' from='primarycontactid' to='contactid' link-type='matchfirstrowusingcrossapply'>
<attribute name='accountid' />
<attribute name='name' />
</link-entity>
</entity>
</fetch>
SQL
select
"contact0".fullname as "fullname",
"account1".accountid as "accountid",
"account1".name as "name"
from Contact as "contact0"
cross apply (
select top 1
"account1".accountid as "accountid",
"account1".name as "name"
from Account as "account1"
where "contact0".contactid = "account1".primarycontactid
) "account1"
局限性
一个查询最多可以添加15个link-entity
元素。每个链接实体都会向查询添加一个JOIN,并增加执行查询的时间。此限制是为了保护性能。如果向查询添加了超过15个link-entity
元素,则会出现以下错误:
Code:
0x8004430D
Number:-2147204339
Message:Number of link entities in query exceeded maximum limit.
对行进行排序 (Order rows)
升序排列
若要指定表中行的排序顺序,请使用 entity 或 link-entity 元素中的 order
元素。默认排序顺序为升序。
下面的查询按createdon
、name
和accountnumber
的值升序返回客户记录。
<fetch>
<entity name='account'>
<attribute name='name' />
<attribute name='accountnumber' />
<attribute name='createdon' />
<order attribute='createdon' />
<order attribute='name' />
<order attribute='accountnumber' />
</entity>
</fetch>
元素的顺序决定了如何应用排序。要使用accountnumber
应用排序,请将该元素移动到第一个位置。
降序排列
如果要使用降序排列,请将descending
属性设置为true
。下面的示例返回客户记录,顶部是最近创建的记录。
<fetch>
<entity name='account'>
<attribute name='name' />
<attribute name='createdon' />
<order attribute='createdon' descending='true' />
</entity>
</fetch>
首先处理link-entity
排序
Dataverse总是将link-entity指定的属性排在实体元素的属性之后。
下面的示例显示了link-entity
属性和entity
属性的常规排序模式。
<fetch>
<entity name='account'>
<attribute name='name' />
<attribute name='accountnumber' />
<attribute name='createdon' />
<link-entity name='account'
from='accountid'
to='parentaccountid'
link-type='inner'
alias='parentaccount'>
<attribute name='name'
alias='parentaccount' />
<!-- The link-entity parentaccount name -->
<order attribute='name' />
</link-entity>
<!-- The entity account name -->
<order attribute='name' />
</entity>
</fetch>
在这种情况下,结果使用以下属性排序:
- First =>
account.name
- Last =>
parentaccountname.name
要确保首先应用link-entity
顺序,请将order
元素从link-entity
元素移动到另一个order
元素上方的entity
元素,并使用order
元素上的entityname
属性来引用link-entity
alias
值。
<fetch>
<entity name='account'>
<attribute name='name' />
<attribute name='accountnumber' />
<attribute name='createdon' />
<link-entity name='account'
from='accountid'
to='parentaccountid'
link-type='inner'
alias='parentaccount'>
<attribute name='name'
alias='parentaccount' />
</link-entity>
<!-- The link-entity parentaccount name -->
<order entityname='parentaccount'
attribute='name' />
<!-- The entity account name -->
<order attribute='name' />
</entity>
</fetch>
现在,使用以下属性对结果进行排序:
- First =>
parentaccount.name
- Last =>
account.name
过滤行 (Filter rows)
filter
若要对要返回的数据行设置条件,请在实体、链接实体或其他元素中使用 filter 元素。
要设置条件,请向filter
添加一个或多个 condition
元素。包含filter
type
确定是否必须满足所有(and
)或任何(or
)条件。默认值是and
。通过嵌套筛选元素,您可以创建复杂的filter
条件,将使用and
或or
评估的条件组合在一起。
filter type='and'
例如,下面的查询返回address1_city等于'Redmond'的帐户记录。它使用eq
操作符。
<fetch>
<entity name='account'>
<attribute name='name' />
<filter type='and'>
<condition attribute='address1_city'
operator='eq'
value='Redmond' />
</filter>
</entity>
</fetch>
filter type='or'
这个查询返回address1_city等于'Redmond'、'Seattle'或'Bellevue'的帐户记录。它使用eq
操作符。
<fetch>
<entity name='account'>
<attribute name='name' />
<attribute name='address1_city' />
<filter type='or'>
<condition attribute='address1_city'
operator='eq'
value='Redmond' />
<condition attribute='address1_city'
operator='eq'
value='Seattle' />
<condition attribute='address1_city'
operator='eq'
value='Bellevue' />
</filter>
</entity>
</fetch>
对同一行中的列值进行筛选
可以使用valueof
属性创建筛选器,比较同一行中各列的值。例如,如果你想查找任何firstname
列值与lastname
列值匹配的联系人记录,你可以使用这个查询:
<fetch>
<entity name='contact' >
<attribute name='firstname' />
<filter>
<condition attribute='firstname'
operator='eq'
valueof='lastname' />
</filter>
</entity>
</fetch>
局限性
在FetchXml查询中包含的条件和链接实体元素总数不能超过500个。否则,你会看到这个错误:
Name:
TooManyConditionsInQuery
Code:0x8004430C
Number:-2147204340
Message:Number of conditions in query exceeded maximum limit.
您需要减少执行查询的条件数量。您可以通过使用in
操作符来减少条件的数量,该操作符可用于数字、唯一标识符和最多850个字符的字符串。