Выберите процент записей с помощью CRM 2011 Dynamic Entity - PullRequest
2 голосов
/ 15 сентября 2011

Я разрабатываю сервис, который использует данные CRM 2011 через динамические сущности (как, например, Microsoft.Xrm.Sdk.Entity, метод позднего связывания).Я намеренно не использую метод Xrm.cs (раннее связывание) в попытке сделать свое решение универсальным.

Кроме того, я хочу избежать прямого подключения к базе данных CRM (например, EDMX), так как это остановит мойРешение может использоваться для размещенной CRM (например, без прямого доступа к БД).

У меня есть следующее (упрощенное) требование, я действительно борюсь с критериями выбора:

A случайные 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 выполнить этот запрос?Есть ли лучший способ сделать это?

Ответы [ 2 ]

2 голосов
/ 17 сентября 2011

Dynamics CRM 2011, на данный момент, не может дать вам степень запросов, которую могут предоставить SQL и другие поставщики LINQ, поэтому я действительно верю, что вы захотите сказать "нет" клиенту и перейти к локальной версии, если он / она хочет такой гибкости.

С учетом сказанного, вариант метода № 1 состоит в том, чтобы вместо выборки всех строк сразу, а затем выбрать случайный наборизвлекайте случайный набор из объекта по одной строке за раз, пока у вас не будет желаемого количества строк.Недостатком этого метода является то, что вместо одного обращения к БД их много, что замедляет общую скорость извлечения.POC ниже.

Что касается # 2, я считаю, что возможно обработать все ваши запросы, с некоторой степенью успеха, используя fetchXml.Фактически, единственный способ получить агрегированные данные - это использовать fetchXml, и он также поддерживает paging .

Что касается # 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);
        }

    }
}
2 голосов
/ 15 сентября 2011

FetchXML не поддерживает это, поэтому у вас до 1 или 3. И вы правы, 3 будет работать только в версии On Premise, поскольку вы не можете напрямую подключиться к SQL с продуктом CRM Online.Тем не менее, я бы с этим согласился, если вы не уверены, что клиент перейдет на CRM Online.Если вам нужно перейти с 1, вы можете как минимум ограничить возвращаемые столбцы только GUID записи, чтобы уменьшить размер полезной нагрузки.Затем, когда вы выбираете свои случайные записи, просто при необходимости получите их дополнительные столбцы (конечно, это может закончиться медленнее из-за «болтливости», в зависимости от того, сколько случайных записей вы имеете дело).

...