2009-11-04 30 views
9

Supongamos que tengo dos clases:propiedades de acceso anidado con lambda dinámico utilizando Linq.Expression

class person 
{ 
    int ID 
    string name 
    Address address 
} 
class address 
{ 
    int ID 
    string street 
    string country 
} 

Estas clases se dan más o menos, que se asignan a través de NHibernate para ser honesto :)

En una grilla (datatables.net como base) me gustaría tener una clasificación independiente del tipo.

Por lo tanto he creado una expresión lambda:

var param = Expression.Parameter(typeof(T), typeof(T).Name); 
    var sortExpression = Expression.Lambda<Func<T, object>> 
           (Expression.Convert(Expression.Property(param, "Property to sort"), typeof(object)), param); 

Si paso persona que el Tipo T y sustituir a la "propiedad para ordenar" con "nombre" que funciona bien (crea una lambda correcta). Si la propiedad es para ordenar "address.street" no va a funcionar, me tiro el siguiente error:

Property 'address.street' is not defined for type 'person' 

sólo veo una solución hasta el momento, pero no lo suficientemente claro ... Me gustaría tratar de dividir la cadena que contiene el Nombre de la propiedad (dividido por)

¿Alguien puede dar una mejor solución? Necesito agregar sortExpression a un objeto IQueryable query.OrderBy(sortExpression).

No estoy seguro si mi título es claro, por favor, adelante y corríjalo.

Gracias de antemano.

Respuesta

2

Me parece que estás intentando volver a escribir Microsoft DynamicQuery. ¿Por qué no usar eso en su lugar?

He aquí un ejemplo:

IQueryable<Foo> myQuery = GetHibernateQuery(); 
myQuery = myQuery.OrderBy("address.street"); 
+0

Como solo obtengo un objeto IQueryable que ya contiene un montón de datos, luego agrego el paginado y más, luego solo cargo los datos que quedan en la consulta. Esto es hecho por nHibernate. Solo para la clasificación no puede ser la solución (espero) – griti

+0

Ese es mi punto. DynamicQuery ya puede hacer esto "agregar la ordenación a un consultable existente". Tengo una solución demo en mi blog que hace esto. http://blogs.teamb.com/craigstuntz/2009/04/27/38243/ –

+0

oh gracias, leeré a través de él – griti

12

Lo que no está claro?

Hay que dividirlo y luego usar:

Expression.Property(Expression.Property(param, "address"), "street") 
+0

uhm y ¿cómo harías eso si tal vez llega algo así como 'person.company.address.street'? Simplemente no sé cómo "anidarlo" ... o si hay otras formas, como las publicadas por Craig ... – griti

+1

Expression.Property (Expression.Property (Expression.Property (Expression.Property (param, "person")), "compañía"), "dirección"), "calle") Simple loop funcionará. – LukLed

+0

no a mano? :) – griti

4

Aquí hay una versión más genérica de la respuesta de LukLed:

protected MemberExpression NestedExpressionProperty(Expression expression, string propertyName) 
    { 
     string[] parts = propertyName.Split('.'); 
     int partsL = parts.Length; 

     return (partsL > 1) 
      ? 
      Expression.Property( 
       NestedExpressionProperty(
        expression, 
        parts.Take(partsL - 1) 
         .Aggregate((a, i) => a + "." + i) 
       ), 
       parts[partsL - 1]) 
      : 
      Expression.Property(expression, propertyName); 
    } 

Usted puede utilizar de esta manera:

var paramExpression = Expression.Parameter(this.type, "val"); 
var firstProp = NestedExpressionProperty(paramExpression,"address.street"); 
+0

Este es un método excelente y reutilizable para resolver este problema. Gracias. –

+0

Excelente respuesta +1. Puede hacer esto en un trazador de líneas: 'return propertyName.Split ('.'). Aggregate (expression, (body, member) => Expression.PropertyOrField (body, member));'. – nawfal

+0

Si no te gustan los cruzados de línea de lujo, quizás una versión más legible es 'foreach', como:' Expression body = expression; foreach (miembro var en propertyName.Split ('.')) { body = Expression.PropertyOrField (body, member); } cuerpo de devolución; ' – nawfal

0

Pruebe este de

public static IQueryable<T> SortIQueryable<T>(IQueryable<T> data, string fieldName, string sortOrder) 
    { 
     if (string.IsNullOrWhiteSpace(fieldName)) return data; 
     if (string.IsNullOrWhiteSpace(sortOrder)) return data; 

     var param = Expression.Parameter(typeof(T), "i"); 

     MemberExpression property = null; 
     string[] fieldNames = fieldName.Split('.'); 
     foreach (string filed in fieldNames) 
     { 
      if (property == null) 
      { 
       property = Expression.Property(param, filed); 
      } 
      else 
      { 
       property = Expression.Property(property, filed); 
      } 
     } 

     Expression conversion = Expression.Convert(property, typeof(object));//Expression.Property(param, fieldName) 
     var mySortExpression = Expression.Lambda<Func<T, object>>(conversion, param); 

     return (sortOrder == "desc") ? data.OrderByDescending(mySortExpression) 
      : data.OrderBy(mySortExpression); 
    } 
Cuestiones relacionadas