我正在开发通过动态实体消费CRM 2011数据的服务(如Microsoft.Xrm.Sdk.Entity,后期绑定方法)。我故意不使用Xrm.cs方法(早期绑定)来试图保持我的解决方案的通用性。
另外,我想避免直接连接到CRM数据库(例如EDMX),因为这会阻止我的解决方案可用于托管CRM(例如,没有直接的DB访问)。
我有以下(简化)要求,我真的很难选择标准:
随机7%记录需要选择(并更新)。
在SQL中,选择标准相对容易 - 我知道如何选择随机百分比的记录。类似的东西:
SELECT TOP 7 PERCENT * FROM
(
SELECT TOP 1000 NEWID() AS Foo, [someColumns]
FROM [someTable]
)
AS Bar ORDER BY Bar.Foo ASC
这完美无缺。我收集的LINQ等价物是这样的:
from e in someEntities
orderby Guid.NewGuid()
select e;
但是有一个问题,我不知道如何将LINQ与CRM 2011动态实体一起使用 - 相反,他们坚持使用一些限制性QueryExpression类/语法或fetchXML,如this page (MSDN)所示。
我已确定以下选项来满足此要求:
使用动态实体,将整个记录集返回到List中,然后只需按索引选择随机选择。然而,这涉及通过互联网数据服务返回多达10,000条记录,这可能是缓慢/不安全/等。
使用fetchXML语句。不幸的是我不知道fetchXML,所以我不知道是否可以做COUNT,TOP,PERCENT或NEWID()等事情。
使用Xrm.cs和LINQ,或使用存储过程或SQL视图。所有这些选项意味着将解决方案与直接数据库连接和/或早期绑定联系起来,这是不可取的。
对客户说不。
任何建议将不胜感激! fetchXML可以执行此查询吗?有更好的方法吗?
答案 0 :(得分:2)
FetchXML不支持此功能,因此您可以使用1或3.而且您是对的,3只能在On Premise版本中运行,因为您无法使用CRM Online产品直接连接到SQL。但是,除非您完全确定客户将转向CRM Online,否则这就是我要去的那个。如果必须使用1,则至少可以将返回的列限制为记录的GUID以减小有效负载大小。然后,当你选择你的随机记录时,如果需要的话就去获取他们的额外列(当然,由于“chattiness”,这可能会因为“chattiness”而变慢,这取决于你正在处理的随机记录数量。)
答案 1 :(得分:2)
话虽如此,方法#1的一个变体是,而不是一次获取所有行,然后选择随机集,一次从实体获取一个随机集,直到你有你的行数想。这种方法的缺点是,不是一次调用DB,而是有许多调用,这会降低整体检索速度。 POC在下面。
对于#2,我相信使用fetchXml可以在一定程度上成功处理您的所有请求。实际上,获取aggregated data的唯一方法是使用fetchXml,它还支持paging。
至于#3,本地SQL是你在这一点上获得你想要的所有内容的最佳选择,但是尽管如此,在the LINQ provider is limited时,将SQL语句转换为LINQ要比将其转换为LINQ要容易得多。 fetchXML和it does support late-binding/dynamic entities。
//create a list of random numbers
List<int> randomNumbers = new List<int>();
//declare a percentage of records you'd like to retrieve
double pctg = 0.07;
//use FetchXML to count the # of rows in the table
string fetchXml = @"<fetch aggregate='true'>
<entity name='salesorder'>
<attribute name='salesorderid' aggregate='count' alias='countIds' distinct='false' />
</entity>
</fetch>";
EntityCollection result = _service.RetrieveMultiple(new FetchExpression(fetchXml));
int rowCount = int.Parse(result.Entities[0].FormattedValues["countIds"].Replace(",", ""));
//initalize the random number list for paging
for (int i = 0; i < Math.Ceiling(pctg * rowCount); i++)
{
randomNumbers.Add((new Random(unchecked((int)(DateTime.Now.Ticks >> i)))).Next(rowCount - 1));
}
randomNumbers.Sort();
//page through the rows one at a time until you have the number of rows you want
using (OrganizationServiceContext osc = new OrganizationServiceContext(_service))
{
foreach (int r in randomNumbers)
{
foreach (var er in (from c in osc.CreateQuery("salesorder")
//not especially useful to use the orderby option as you can only order by entity attributes
//orderby c.GetAttributeValue<string>("name")
select new
{
name = c.GetAttributeValue<string>("name")
}).Skip(r).Take(1))
{
Console.WriteLine(er.name);
}
}
}