2013-07-15 46 views
10

Tôi đang sử dụng hàm orderq linq động này mà tôi nhận được từ here.Thứ tự linq động theo thuộc tính lồng nhau với thuộc tính null

này hoạt động tốt với các thuộc tính lồng nhau vì vậy tôi có thể làm điều này:

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

Vấn đề là nếu SomeProperty là null sau đó thực hiện OrderBy trên NestedProperty ném "tài liệu tham khảo đối tượng khét tiếng không được đặt để một thể hiện của một đối tượng".

tôi đoán là tôi cần để tùy chỉnh các dòng sau để xử lý các ngoại lệ:

expr = Expression.Property(expr, pi); 

// Or 

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

Tôi nghĩ về việc tạo ra một cơ thể tuyên bố nơi tôi có thể trong trường hợp xấu nhất sử dụng một catch nhưng điều đó didn' Nếu bạn không thể có các câu lệnh trong câu lệnh linq: "Biểu thức lambda có thân xác nhận không thể chuyển thành cây biểu thức"

Tôi bị mất ở đây, mọi đề xuất về cách tôi có thể thực hiện điều này ?

Nhân tiện, điều này là dành cho LINQ đối tượng, không phải liên quan đến cơ sở dữ liệu.

+0

Tôi đoán dòng này 'expr = Expression.Property (expr, pi);' bộ 'expr' null và mã hơn nữa không xử lý nó. Cách dễ nhất để sửa chữa nó là 'expr = Expression.Property (expr, pi) ?? mặc định (T); Tuy nhiên, bạn sẽ cần kiểm tra xem bạn có đồng ý với đơn đặt hàng được áp dụng trong trường hợp này hay không. – Tommi

+0

Đó là một điểm tốt, thực sự sẽ làm cho công việc sắp xếp sai, lý tưởng là các giá trị rỗng phải được "nhóm lại" với nhau. –

+0

xem nếu điều này giúp bạn trong bất kỳ cách nào http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet?lq=1 – Ehsan

Trả lời

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

Xuất sắc, cái này trông đơn giản hơn câu trả lời của Marc Gravel, điều này làm tôi ngạc nhiên. Tuy nhiên, tất cả các thử nghiệm của tôi dường như làm việc tốt và bạn đã làm cho tôi một người đàn ông hạnh phúc. –

+0

Rất thông minh. Nice trick với đệ quy. Microsoft nên cung cấp điều này như là một phương pháp mở rộng trong các khung công tác trong tương lai. – arviman

+0

Điều gì xảy ra nếu thay vì SomeProperty bạn có một List ? Mã trên cần được sửa đổi như thế nào để đối phó với trường hợp đó? – demonicdaron

3

Làm thế nào về Generics:

Helper Method:

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

mẫu Hierarchy:

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

Ví dụ:

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

Bạn là thiên tài, cảm ơn bạn rất nhiều! – Alexander

Các vấn đề liên quan