2011-02-09 1 views
12

Я написал запрос Linq для CRM, используя CRM-провайдер CRM 2011 RC (v5) LINQ-to-CRM. У меня есть локально объявленный список <T>, который я хочу присоединиться к объекту CRM, и я хочу, чтобы запрос выполнялся на сервере CRM. Пример может помочь:LINQ to Dynamics CRM записи фильтрации запросов локально

MyObject myObject = new MyObject(); 
List<myAccount> myAccountsList = new List<myAccount>(); 

myAccountsList.Add(new myAccount() {AccountNumber = "123"}; 
myAccountsList.Add(new myAccount() {AccountNumber = "456"}; 

myObject.ListOfAccounts = myAccountsList; 

var accountsQuery = from ax in myObject.ListOfAccounts 
        join a in orgContext.CreateQuery<customAccountEntity>() on ax.AccountNumber equals a.account_number 
        select a; 

foreach(var item in accountsQuery) 
{ 
    Console.WriteLine("Id of record retrieved: " + a.Id.ToString()); 
} 

Код выше компилирует и выполняет, однако, фильтрация записей выполняется локально, после извлечения всей CRM-сущностей записей. Очевидно, что когда объект CRM содержит тысячи строк, запрос будет выполнять плохо или даже таймаут.

Я прочитал о IQueryable и IEnumerable и попытался преобразовать список, используя метод расширения AsQueryable(), который не имел никакого эффекта. Мне нужно выше Linq запрос для запуска SQL как это:

SELECT a.* 
FROM customAccountEntity AS a 
WHERE a.account_number IN ('123', '456'); 

Или используя временную таблицу, если хотел присоединиться по нескольким полям. Как я могу это сделать?

ответ

12

После много головокружений и исследований я решил проблему, используя Predicate Builder и LINQKit. Мне нужно создать предикат на основе Or, используя ключи в моем локальном списке < T>, затем передайте предикат методу расширения Where LINQ. Важно отметить, что мне нужно вызвать метод расширения AsExpandable, открытый LINQKit. Так что мой код будет выглядеть следующим образом:

var predicate = PredicateBuilder.False<customAccountEntity>(); 
// Loop through the local List creating an Or based predicate 
foreach (var item in myAccountsList) 
{ 
    string temp = item.AccountNumber; 
    predicate = predicate.Or (x => x.customCrmEntityAttribute == temp); 
} 
// The variable predicate is of type Expression<Func<customAccountEntity, bool>> 
var myLinqToCrmQuery = from ax in myObject.ListOfAccounts 
         from cx in orgContext.CreateQuery<customAccountEntity>().AsExpandable().Where(predicate) 
         where ax.AccountNumber == cx.account_number 
         select cx; 

foreach (resultItem in myLinqToCrmQuery) 
{ 
    Console.WriteLine("Account Id: " + resultItem.Id); 
} 

Приведенный выше код будет работать инструкции SQL на сервере CRM, как это:

SELECT a.* 
FROM customAccountEntity AS a 
WHERE a.account_number = '123' OR a.account_number = '456' 

Это означает, что я могу создать динамичный, где положение во время выполнения и знать что мой запрос будет запускать логику фильтрации на CRM SQL Server. Надеюсь, это поможет кому-то другому.

0

Edit: Попробуйте, что один:

MyObject myObject = new MyObject(); 
List<myAccount> myAccountsList = new List<myAccount>(); 

myAccountsList.Add(new myAccount() {AccountNumber = "123"}; 
myAccountsList.Add(new myAccount() {AccountNumber = "456"}; 

myObject.ListOfAccounts = myAccountsList; 

var accountNumbers = myObject.ListOfAccounts.Select(a => a.AccountNumber); 

var accountsQuery = orgContext.CreateQuery<customAccountEntity>() 
           .Where(a => accountNumbers.Contains(a.account_number)); 

foreach(var item in accountsQuery) 
{ 
    Console.WriteLine("Id of record retrieved: " + a.Id.ToString()); 
} 

Edit: если вы запрашиваете провайдер не поддерживает Содержит, построить Where состояние с множественным ИЛИ, вы можете использовать predicate builder, чтобы сделать это легко

+0

Я уже использую поставщика запроса Linq-на-УРК - Могу ли я использовать более одного провайдера в одном запросе? – Iftekhar

+0

Хорошо, посмотрев поближе к вашему запросу, я думаю, вы должны сделать это наоборот (нет соединения, но содержит) – Guillaume86

+0

Я хочу, чтобы мой запрос был переведен на SQL и фильтрацию для запуска на SQL Server. Метод Содержит метод просто фильтрует локально. – Iftekhar

1

Вместо того чтобы играть с предикатами, вы также можете просто использовать выражение объединения для фильтрации.

var myLinqToCrmQuery = from ax in myObject.ListOfAccounts 
          join cx in orgContext.CreateQuery<customAccountEntity> on ax.AccountNumber equals cx.account_number      
          select cx; 

Cheers, Лукаш

+1

Я хотел, чтобы запрос запускался на сервере. С помощью выражения join фильтрация выполняется локально на клиенте. – Iftekhar

Смежные вопросы