2009-04-20 4 views
7

Tengo algunas consultas de linq que tienen redundancia. Me gustaría restarle un factor de código. Se trata de extensiones de unión que son IQueryable, y es importante que no haga que la consulta se evalúe antes de lo que sería sin la refactorización.refactorización de la expresión IQueryable de LINQ para eliminar partes duplicadas de las consultas

Aquí es una consulta simplificada:

var result = 
from T in db.Transactions 
join O in db.Orders on T.OrderID equals O.OrderID 
join OD in db.OrderDetails on O.OrderID equals OD.OrderID into OrderDetails 
let FirstProductBought = OrderDetails.First().Select(OD => OD.Product.ProductName) 
select new 
{ 
    TransactionID = T.TransactionID, 
    OrderID = O.OrderID, 
    FirstProductBought = FirstProductBought 
}; 

Lo que quiero es factorizar º lógica "dado una orden, lo que es el primer artículo, han comprado". Estoy usando la misma lógica en otras consultas. ¿Cómo puedo factorizarlo en un método compartido?

En general, para la reutilización de código y IQueryables, lo que he podido hacer es un código que toma un IQueryable entrando y produce un IQueryable/IOrderedQueryable como salida. Con tales funciones puedo construir expresiones LINQ con código reutilizable que aún difieren la consulta hasta que la consulta esté completamente construida. Aquí, dado que solo tengo un int (el ID de pedido), no estoy seguro de cómo hacerlo funcionar.

gracias

+0

Esta es una gran pregunta de alto nivel para Linq'ers. Le pregunté lo mismo básico y no he recibido mucho feedback. – Merritt

Respuesta

4

este momento para responder a mi propia pregunta, pero he encontrado una buena solución. Sin embargo, creo que dependiendo de lo que intentes hacer, hay diferentes formas de factorizar diferentes expresiones LINQ sin evaluar IQueryable. Así que espero que las personas compartan soluciones alternativas.

Mi solución fue crear una "vista" para la consulta factorizada. Lo llamo una vista porque tiene mucho en común con una vista SQL (desde la perspectiva de un cliente LINQ). Sin embargo, a diferencia de una vista SQL, no se puede indexar ni tener columnas persistentes. Entonces, usar esta vista se convierte en un cuello de botella, sería apropiado usar una vista SQL real.

static public class MyDataContextExtension 
{ 
    // The view exposes OrderSummary objects 
    public class OrderSummary 
    { 
     public OrderID { get; set; } 
     public string FirstProductListed { get; set; } 
    } 

    static public IQueryable<OrderSummary> OrderySummaryView(this MyDataContext db) 
    { 
     return (
       from O in db.Orders 
       join OD in db.OrderDetails on O.OrderID equals OD.OrderID into OrderDetails 
       let AProductBought = OrderDetails.First().Select(OD => OD.Product.ProductName) 
       let TotalCost = OrderDetails.Aggregate(0 
       select new OrderSummary() 
       { 
        OrderID = OD.OrderID, 
        FirstProductListed = AProductBought.FirstOrDefault() 
       }; 
    } 
} 

Con esto, se puede factorizar la parte duplicada de la consulta, en sustitución de la consulta original con lo siguiente:

var result = 
from T in db.Transactions 
join OS in db.OrderSummaryView() on T.OrderID equals OS.OrderID 
select new 
{ 
    TransactionID = T.TransactionID, 
    OrderID = T.OrderID, 
    FirstProductBought = OS.FirstProductListed 
}; 

Se puede imaginar que se agregan otras columnas ... Creo que uno fresco Lo que sucede es que si agrega columnas adicionales pero no las utiliza en su selección final, LINQ no consultará esas cosas desde la base de datos.

1

Tuvimos el mismo problema. No es compatible desde el primer momento y es un problema importante para las aplicaciones de LOB. Terminé escribiendo un artículo sobre el proyecto de código sobre reutilización de expresiones LINQ, que incluye una utilidad muy pequeña llamada LinqExpressionPrjection que permite la reutilización en proyecciones (incluso en tipos anónimos).

Encuentra el artículo here.

Puede obtener el conjunto para la reutilización de proyección como nuget package y la fuente está en CodePlex.

Ha pasado algún tiempo desde su publicación. Espero que aún sea útil para ti. Si no, tal vez para otros que leen este hilo.

+0

gracias! ¿Quiso vincularse a http://www.codeproject.com/Articles/402594/Black-Art-LINQ-expressions-reuse? Para mí, el enlace del artículo que le dio carga a una lista de sus artículos. –

0

Otra forma importante tener en cuenta las expresiones LINQ es pasar expresiones en torno, por ejemplo:

X GetSomeX(Expression<Func<Y, X>> map) 
{ 
    return SourceOfYs.Select(map); 
} 

me ocurrió la idea mirando en el artículo del artículo de Barak - ya pesar de que lo hace un poco más sobre esto tema, pensé que volvería a mencionar esta pieza aquí. Parece ser una primera cosa obvia para señalar directamente.

Cuestiones relacionadas