2011-02-09 14 views
12

he escrito una consulta LINQ a CRM utilizando CRM 2011 RC (v5) proveedor de LINQ-a-CRM. Tengo una lista localmente declarada <T> que quiero unir a una entidad CRM y quiero que la consulta se ejecute en el servidor CRM. Un ejemplo puede ayudar a:LINQ para filtrar registros Dynamics CRM de consulta a nivel local

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

El código anterior se compila y ejecuta, sin embargo, el filtrado de los registros se está realizando a nivel local después de recuperar la totalidad del conjunto de registros entidad CRM. Obviamente, cuando la entidad CRM contiene miles de filas, la consulta tendrá un rendimiento bajo o incluso un tiempo de espera excedido.

He leído sobre IQueryable y IEnumerable y trató de convertir la lista utilizando el método de extensión AsQueryable(), que no tuvo ningún efecto. Necesito mi anterior consulta LINQ para ejecutar SQL como esto:

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

o usando una tabla temporal si se desea unirse en múltiples campos. ¿Cómo puedo lograr esto?

Respuesta

12

Después un montón de golpes de cabeza e investigación. He resuelto el problema usando Predicate Builder y LINQKit. Necesito crear un predicado basado O usando las teclas en mi lista local < T> a continuación, pasar el predicado a la Dónde método de extensión de LINQ. Es importante destacar que debo llamar al AsExpandable método de extensión expuesto por LINQKit. Así que mi código se vería así:

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

El código anterior se ejecutará una instrucción SQL en el servidor de CRM como esto:

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

Esto significa que puede crear una dinámica en la que la cláusula en tiempo de ejecución y saber que mi consulta ejecutará la lógica de filtrado en CRM SQL Server. Espero que esto ayude a alguien más.

0

Editar: Trate de que uno:

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

Editar: si se consulta el proveedor no soporte contiene, construir una condición en la que con múltiples O, puede utilizar predicate builder para hacer tan fácil

+0

ya estoy usando el proveedor de consulta LINQ-a-CRM - ¿Puedo utilizar más de un proveedor en la misma consulta? – Iftekhar

+0

Ok, después de mirar más de cerca tu consulta, creo que deberías hacerlo al revés (sin unir sino con un contenido) – Guillaume86

+0

Quiero que mi consulta se traduzca a SQL y que el filtrado se ejecute en SQL Server. El método de extensión Contiene simplemente filtra localmente. – Iftekhar

1

En lugar de jugar con los predicados se podría también utilizar simplemente la expresión de combinación para el filtrado.

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

Cheers, Lukasz

+1

Quería que la consulta se ejecutara en el servidor. Con la expresión de unión, el filtrado se realiza localmente en el cliente. – Iftekhar

Cuestiones relacionadas