使用 CRM 2011 动态实体选择记录的百分比

发布于 2024-12-04 22:22:16 字数 1229 浏览 2 评论 0原文

我正在开发通过动态实体(如 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 可以执行这个查询吗?有更好的方法吗?

I'm developing service which consumes CRM 2011 data via dynamic entities (as in, Microsoft.Xrm.Sdk.Entity, the late-binding method). I'm deliberately not using Xrm.cs method (early binding) in an attempt to keep my solution generic.

Also, I want to avoid connecting to a CRM database directly (e.g. EDMX) as this would stop my solution being usable for a hosted CRM (e.g. with no direct DB access).

I have the following (simplified) requirement, I'm really struggling with the selection criteria:

A random 7% of records needs to be selected (and updated).

In SQL, the selection criteria would be relatively easy - I know how to select a random percentage of records. Something like:

SELECT TOP 7 PERCENT * FROM
(
    SELECT TOP 1000 NEWID() AS Foo, [someColumns]
    FROM [someTable]
)
AS Bar ORDER BY Bar.Foo ASC

This works perfectly. I gather the LINQ equivalent is something like:

from e in someEntities
orderby Guid.NewGuid()
select e;

There's a problem though, I don't know of a way to use LINQ with CRM 2011 dynamic entities - instead they insist on using either some restrictive QueryExpression classes/syntax, or fetchXML, as seen on this page (MSDN).

I've identified the following options for fulfilling this requirement:

  1. Using dynamic entities, return the whole record set into a List, then simply choose a random selection by index. This however involves returning up to 10,000 records over an internet data service, which may be slow/insecure/etc.

  2. Use a fetchXML statement. Unfortunately I don't know fetchXML, so I don't know if it's possible to do things like COUNT, TOP, PERCENT or NEWID().

  3. Use Xrm.cs and LINQ, or use a Stored Procedure, or a SQL view. All of these options mean tying the solution down to either direct database connectivity and/or early binding, which is not desirable.

  4. Say no to the customer.

Any advise would be greatly appreciated! Can fetchXML perform this query? Is there a better way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

第七度阳光i 2024-12-11 22:22:16

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

FetchXML does not support this, so you are down to either 1 or 3. And you are right, 3 would only work in the On Premise version, as you can't connect directly to SQL with the CRM Online product. However, that's the one I would go with unless you are absolutely sure the customer will be moving to CRM Online. If you must go with 1, you can at least limit the returned columns to only be the GUID of the record to decrease the payload size. Then when you select your random records, just go get their additional columns if needed (of course this could end up being slower due to "chattiness" depending on how many random records you are dealing with).

愁杀 2024-12-11 22:22:16

目前,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);
        }

    }
}

Dynamics CRM 2011, at this point, can't give you the degree of querying power that SQL and other LINQ providers can give, so I really believe you'll want to say no to the customer and move to the on-premise version if he/she wants that kind of flexibility.

With that said, a variant of method #1 is to, rather than fetch all rows at once and then choose your random set, fetch a random set from the entity one row at a time until you have the number of rows you want. The downside of this method is that instead of one call to the DB, there are many, which slows down the overall retrieve speed. A POC is below.

As for #2, I believe it's possible to handle all of your request, with some degree of success, using fetchXml. In fact, the only way to get aggregated data is by using fetchXml, and it also supports paging.

As for #3, native SQL is your best bet to get everything you want out of your data at this point, but that notwithstanding, while the LINQ provider is limited, it's a lot easier to transition SQL statements to LINQ than to fetchXML, and 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);
        }

    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文