2013-07-15 12 views
10

Ich benutze diese dynamische linq orderby-Funktion, die ich von here erhalten habe.Dynamische Linq-Reihenfolge von einer verschachtelten Eigenschaft mit Null-Eigenschaften

Dies funktioniert mit verschachtelten Eigenschaften fein so dass ich dies tun könnte:

var result = data.OrderBy("SomeProperty.NestedProperty"); 

Das Problem ist, dass, wenn SomeProperty null die OrderBy auf dem NestedProperty dann ist die Durchführung des berüchtigten „Objektverweis nicht gesetzt wirft auf eine Instanz ein Objekt".

Meine Vermutung ist, dass ich die folgenden Zeilen anpassen, um die Ausnahme zu behandeln:

expr = Expression.Property(expr, pi); 

// Or 

LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);  

Ich dachte an eine Aussage Körper zu schaffen, wo ich im schlimmsten Fall einen Versuch fängt aber, dass didn verwenden könnte‘ t arbeiten, da Sie keine Anweisungskörper in orderby linq-Anweisungen haben können: "Ein Lambda-Ausdruck mit einem Anweisungskörper kann nicht in einen Ausdrucksbaum konvertiert werden"

Ich bin hier verloren, irgendwelche Vorschläge, wie ich dies erreichen kann ?

Übrigens ist dies für Linq zu Objekten, nicht Datenbank bezogen.

+0

Ich denke, diese Zeile 'expr = Expression.Property (expr, pi);' 'expr' Sätze null und weiteren Code ist es nicht handhaben. Der einfachste Weg, um es zu beheben, ist 'expr = Expression.Property (expr, pi) ?? Standard (T); '. Allerdings müssen Sie in diesem Fall überprüfen, ob Sie mit der angewandten Reihenfolge einverstanden sind. – Tommi

+0

Es ist ein guter Punkt, eigentlich würde das Sortieren falsch funktionieren, idealerweise sollten die Nullen "gruppiert" werden. –

+0

sehen, ob dies Ihnen in irgendeiner Weise hilft http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet?lq=1 – Ehsan

Antwort

5
static void Main(string[] args) 
{ 
    var data = new List<MyType>() { 
     new MyType() { SomeProperty = new Inner() { NestedProperty = "2" }}, 
     new MyType() { SomeProperty = new Inner() { NestedProperty = "1" }}, 
     new MyType() { SomeProperty = new Inner() { NestedProperty = "3" }}, 
     new MyType(), 
    }.AsQueryable(); 
    var sorted = data.OrderBy(x => GetPropertyValue(x, "SomeProperty.NestedProperty")); 

    foreach (var myType in sorted) 
    { 
     try 
     { 
      Console.WriteLine(myType.SomeProperty.NestedProperty); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Null"); 
     } 
    } 
} 

public static object GetPropertyValue(object obj, string propertyName) 
{ 
    try 
    { 
     foreach (var prop in propertyName.Split('.').Select(s => obj.GetType().GetProperty(s))) 
     { 
      obj = prop.GetValue(obj, null); 
     } 
     return obj; 
    } 
    catch (NullReferenceException) 
    { 
     return null; 
    } 
} 
+0

Herausragend, dieser sieht einfacher aus als Marc Gravel's Antwort, was mich wundern lässt. Trotzdem scheinen alle meine Tests gut zu funktionieren und du hast mich zu einem glücklichen Mann gemacht. –

+0

Sehr schlau. Netter Trick mit der Rekursion. Microsoft sollte dies als eine Erweiterungsmethode in zukünftigen Frameworks bereitstellen. – arviman

+0

Was ist, wenn Sie anstelle von SomeProperty eine Liste haben? Wie müsste der obige Code geändert werden, um diesen Fall zu behandeln? – demonicdaron

3

Wie wäre es Generika:

Helper-Methode:

public static Expression<Func<TEntity, TResult>> GetExpression<TEntity, TResult>(string prop) 
     { 
      var param = Expression.Parameter(typeof(TEntity), "p"); 
      var parts = prop.Split('.'); 

      Expression parent = parts.Aggregate<string, Expression>(param, Expression.Property); 
      Expression conversion = Expression.Convert(parent, typeof (object)); 

      var tryExpression = Expression.TryCatch(Expression.Block(typeof(object), conversion), 
                Expression.Catch(typeof(object), Expression.Constant(null))); 

      return Expression.Lambda<Func<TEntity, TResult>>(tryExpression, param); 
     } 

Beispielhierarchie:

public class A 
    { 
     public A(B b) 
     { 
      B = b; 
     } 

     public B B { get; set; } 
    } 

    public class B 
    { 
     public B(C c) 
     { 
      C = c; 
     } 

     public C C { get; set; } 
    } 

    public class C 
    { 
     public C(int id) 
     { 
      this.Id = id; 
     } 

     public int Id { get; set; } 
    } 

Beispiel:

var list = new List<B> 
      { 
       new B(new A(new C(1))), 
       new B(new A(new C(2))), 
       new B(new A(new C(3))), 
       new B(new A(null)), 
       new B(null) 
      }.AsQueryable(); 

var ordered = list.OrderByDescending(GetExpression<B, Object>("AProp.CProp.Id")); 

Output:

3 
2 
1 
Null 
Null 
+1

Sie sind Genie, vielen Dank! – Alexander

Verwandte Themen