2012-07-13 9 views
10

Tôi đang cố tạo mệnh đề LINQ OrderBy sử dụng biểu thức lambda với đầu vào của tên cột của thực thể dưới dạng chuỗi (trong biến "sortOn" bên dưới).Xây dựng đơn hàngBiểu thức Lambda dựa trên thuộc tính của thực thể con

Đoạn code dưới đây hoạt động tốt cho một giá trị sortOn như "Code" tạo ra lambda

p => p.Code 

Nhưng tôi cũng muốn sắp xếp vào một tổ chức trẻ em, nơi lambda có thể

p => p.Category.Description 

Vì vậy, trong trường hợp này, tôi chỉ muốn thiết lập sortOn = "Category.Description" và có biểu thức chính xác lamdba được tạo ra.

Điều này có khả thi không? Bất kỳ đề xuất về cách tốt nhất để làm điều này sẽ được hoan nghênh.

Mã này hoạt động tốt đối với trường hợp đơn giản:

var param = Expression.Parameter(typeof (Product), "p"); 

var sortExpression = Expression.Lambda<Func<Product, object>>(
    Expression.Property(param, sortOn), param); 

if (sortAscending ?? true) 
{ 
    products = products.OrderBy(sortExpression); 
} 
else 
{ 
    products = products.OrderByDescending(sortExpression); 
} 

Việc sử dụng hợp cụ thể cho vấn đề này được hiển thị một mạng lưới các dữ liệu và có thể sắp xếp dữ liệu, chỉ đơn giản bằng cách truyền tên cột được sắp xếp quay trở lại máy chủ. Tôi muốn làm cho các giải pháp chung chung, nhưng đã bắt đầu sử dụng một loại cụ thể (sản phẩm trong ví dụ) cho bây giờ.

+0

Tại sao bạn tạo biểu thức theo cách thủ công? –

Trả lời

18

này sẽ tạo ra biểu thức lambda thích hợp:

var sortOn = "Category.Description"; 
var param = Expression.Parameter(typeof(Product), "p"); 
var parts = sortOn.Split('.'); 

Expression parent = param; 

foreach (var part in parts) 
{ 
    parent = Expression.Property(parent, part); 
} 

var sortExpression = Expression.Lambda<Func<Product, object>>(parent, param); 
0

Nếu bạn không cần phải diễn đạt, làm thế nào về:

products = products.Orderby(p1 => p1.Code).ThenBy(p2 => p2.Category.Description) 
2

Bạn có thể sử dụng Dynamic LINQ Query Library để làm điều này một cách dễ dàng. Giả sử bạn có một IQueryable<T> implementation của Product, bạn có thể dễ dàng làm:

IQueryable<Product> products = ...; 

// Order by dynamically. 
products = products.OrderBy("Category.Description"); 

Các bài viết trên blog có link to the libary, và bạn sẽ phải xây dựng/bao gồm các dự án trong giải pháp của bạn mình, nhưng nó hoạt động rất tốt, và phân tích cú pháp rất mạnh mẽ. Nó ngăn bạn tự viết mã phân tích cú pháp; ngay cả đối với một cái gì đó rất đơn giản, nếu các yêu cầu mở rộng, thư viện có bạn bảo hiểm, trong khi một giải pháp homegrown thì không.

Nó cũng có một số toán tử động khác (Select, Where, v.v.) để bạn có thể thực hiện các thao tác động khác.

Không có phép thuật dưới mui xe, nó chỉ phân tích cú pháp các chuỗi bạn truyền và sau đó tạo các biểu thức lambda dựa trên kết quả phân tích cú pháp.

+0

Cảm ơn bạn đã đề xuất. Có khả năng đã đánh dấu câu trả lời, nhưng Tomek đã cho tôi cách tiếp cận mà tôi muốn. Chắc chắn sẽ xem xét điều này như một giải pháp thay thế. – Appetere

0

Hi bạn cũng có thể tạo ra một phương pháp khuyến nông như mà có thể sắp xếp cho bất kỳ độ sâu không chỉ con

 public static IEnumerable<TSource> CustomOrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) 
    { 
     List<string> list=new List<string>(); 
     List<TSource> returnList=new List<TSource>(); 
     List<int> indexList = new List<int>(); 

     if (source == null) 
      return null; 
     if (source.Count() <= 0) 
      return source; 
     source.ToList().ForEach(sc=>list.Add(keySelector(sc).ToString())); //Extract the strings of property to be ordered 

     list.Sort(); //sort the list of strings 

     foreach (string l in list) // extract the list of indexes of source according to the order 
     { 
      int i=0; 
      //list.ForEach(l => 

       foreach (var s in source.ToList()) 
       { 
        if (keySelector(s).ToString() == l) 
         break; 
        i++; 
       } 
       indexList.Add(i); 
     } 
     indexList.ForEach(i=>returnList.Add(source.ElementAt(i))); //rearrange the source according to the above extracted indexes 
     return returnList; 
    } 
} 
public class Name 
{ 
    public string FName { get; set; } 
    public string LName { get; set; } 
} 
public class Category 
{ 
    public Name Name { get; set; } 
} 
public class SortChild 
{ 
    public void SortOn() 
    { 
     List<Category> category = new List<Category>{new Category(){Name=new Name(){FName="sahil",LName="chauhan"}}, 
      new Category(){Name=new Name(){FName="pankaj",LName="chauhan"}}, 
      new Category(){Name=new Name(){FName="harish",LName="thakur"}}, 
      new Category(){Name=new Name(){FName="deepak",LName="bakseth"}}, 
      new Category(){Name=new Name(){FName="manish",LName="dhamaka"}}, 
      new Category(){Name=new Name(){FName="arev",LName="raghaka"}} 
     }; 
     var a = category.CustomOrderBy(s => s.Name.FName); 

    } 

} 

phương pháp tùy chỉnh của nó và ngay bây giờ nó chỉ hoạt động cho tài sản chuỗi chỉ tuy nhiên nó có thể được reactified sử dụng Generics để làm việc cho bất kỳ loại nguyên thủy nào. Hy vọng điều này có thể giúp cho bạn.

0

Đây là phần mở rộng Phương thức OrderBy hoạt động với bất kỳ số tham số lồng nhau nào.

public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, string key, bool asc = true) 
{ 
    try 
    { 
    string orderMethodName = asc ? "OrderBy" : "OrderByDescending"; 
    Type type = typeof(T); 
    Type propertyType = type.GetProperty(key)?.PropertyType; ; 

    var param = Expression.Parameter(type, "x"); 
    Expression parent = param; 

    var keyParts = key.Split('.'); 
    for (int i = 0; i < keyParts.Length; i++) 
    { 
     var keyPart = keyParts[i]; 
     parent = Expression.Property(parent, keyPart); 

     if (keyParts.Length > 1) 
     { 
     if (i == 0) 
     { 
      propertyType = type.GetProperty(keyPart).PropertyType; 
     } 
     else 
     { 
      propertyType = propertyType.GetProperty(keyPart).PropertyType; 
     } 
     } 
    } 

    MethodCallExpression orderByExpression = Expression.Call(
     typeof(Queryable), 
     orderMethodName, 
     new Type[] { type, propertyType }, 
     query.Expression, 
     CreateExpression(type, key) 
    ); 

    return query.Provider.CreateQuery<T>(orderByExpression); 
    } 
    catch (Exception e) 
    { 
    return query; 
    } 
} 

Các CreateExpression phương pháp được sử dụng trong giải pháp của tôi được định nghĩa in this post.

Cách sử dụng phương thức mở rộng OrderBy như sau.

IQueryable<Foo> q = [Your database context].Foos.AsQueryable(); 
IQueryable<Foo> p = null; 

p = q.OrderBy("myBar.name"); // Ascending sort 
// Or 
p = q.OrderBy("myBar.name", false); // Descending sort 
// Materialize 
var result = p.ToList(); 

Loại Foo và tính chất của nó cũng được lấy từ bài tương tự như phương pháp CreateExpression.

Hy vọng bạn thấy bài đăng này hữu ích.