2

我正在开发通过动态实体(如 Microsoft.Xrm.Sdk.Entity,后期绑定方法)使用 CRM 2011 数据的服务。我故意不使用 Xrm.cs 方法(早期绑定)以保持我的解决方案通用。

此外,我想避免直接连接到 CRM 数据库(例如 EDMX),因为这会阻止我的解决方案可用于托管 CRM(例如,没有直接的数据库访问)。

我有以下(简化的)要求,我真的在为选择标准苦苦挣扎:

需要选择(并更新)随机 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,如本页 (MSDN)所示。

我已经确定了满足此要求的以下选项:

  1. 使用动态实体,将整个记录集返回到列表中,然后简单地按索引选择随机选择。然而,这涉及通过互联网数据服务返回多达 10,000 条记录,这可能会很慢/不安全/等等。

  2. 使用 fetchXML 语句。不幸的是,我不知道 fetchXML,所以我不知道是否可以执行 COUNT、TOP、PERCENT 或 NEWID() 之类的操作。

  3. 使用 Xrm.cs 和 LINQ,或使用存储过程或 SQL 视图。所有这些选项都意味着将解决方案绑定到直接数据库连接和/或早期绑定,这是不可取的。

  4. 对客户说不。

任何建议将不胜感激!fetchXML 可以执行这个查询吗?有一个更好的方法吗?

4

2 回答 2

2

FetchXML 不支持这一点,因此您只能选择 1 或 3。您是对的,3 仅适用于 On Premise 版本,因为您无法使用 CRM Online 产品直接连接到 SQL。但是,除非您绝对确定客户将迁移到 CRM Online,否则我会采用这种方法。如果必须使用 1,则至少可以将返回的列限制为仅作为记录的 GUID 以减少有效负载大小。然后,当您选择随机记录时,只需在需要时获取它们的附加列(当然,由于“闲聊”,这最终可能会变慢,具体取决于您正在处理的随机记录数量)。

于 2011-09-15T18:03:59.533 回答
2

在这一点上,Dynamics CRM 2011 无法为您提供 SQL 和其他 LINQ 提供程序可以提供的查询能力,所以我真的相信您会想要对客户说不如果他/她想要这种灵活性,请转到本地版本。

话虽如此,方法#1的一个变体是,而不是一次获取所有行然后选择您的随机集,而是一次从实体中获取一个随机集一行,直到您获得所需的行数。这种方法的缺点是对数据库的调用不是一次,而是多次,这会降低整体检索速度。POC 如下。

至于#2,我相信使用 fetchXml 可以处理您的所有请求,并取得一定程度的成功。实际上,获取聚合数据的唯一方法是使用 fetchXml,并且它还支持分页

至于#3,本机 SQL 是您此时从数据中获取您想要的一切的最佳选择,但尽管如此,虽然LINQ 提供程序是有限的,但将 SQL 语句转换为 LINQ 比 fetchXML 容易得多,并且它确实支持后期绑定/动态实体

//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);
        }

    }
}
于 2011-09-17T06:45:25.717 回答