2009-03-17 40 views
14

Tôi đã sử dụng biểu thức C# trước dựa trên lamdas, nhưng tôi không có kinh nghiệm soạn thảo chúng bằng tay. Với số Expression<Func<SomeType, bool>> originalPredicate, tôi muốn tạo một số Expression<Func<OtherType, bool>> translatedPredicate.C# Làm thế nào để chuyển đổi một biểu thức <Func <SomeType>> thành biểu thức <Func <OtherType>>

Trong trường hợp này SomeType và OtherType có cùng các trường, nhưng chúng không liên quan (không thừa kế và không dựa trên giao diện chung).

Thông tin cơ bản: Tôi có triển khai kho lưu trữ dựa trên LINQ to SQL. Tôi chiếu các thực thể LINQ to SQL vào các thực thể Model của tôi, để giữ mô hình của tôi trong POCO. Tôi muốn chuyển các biểu thức vào kho lưu trữ (dưới dạng một đặc tả) nhưng chúng phải dựa trên các thực thể mô hình. Nhưng tôi không thể chuyển những biểu thức đó vào bối cảnh dữ liệu, vì nó mong đợi các biểu thức dựa trên các thực thể LINQ to SQL.

+1

Phản hồi có trong chủ đề này: http://stackoverflow.com/questions/4601844/expression-tree-copy-or-convert – jeanlou1370

Trả lời

20

Với Expression, cách đơn giản nhất là với một chuyển đổi biểu:

class Foo { 
    public int Value { get; set; } 
} 
class Bar { 
    public int Value { get; set; } 
} 
static class Program { 
    static void Main() { 
     Expression<Func<Foo, bool>> predicate = 
      x => x.Value % 2 == 0; 
     Expression<Func<Bar, Foo>> convert = 
      bar => new Foo { Value = bar.Value }; 

     var param = Expression.Parameter(typeof(Bar), "bar"); 
     var body = Expression.Invoke(predicate, 
       Expression.Invoke(convert, param)); 
     var lambda = Expression.Lambda<Func<Bar, bool>>(body, param); 

     // test with LINQ-to-Objects for simplicity 
     var func = lambda.Compile(); 
     bool withOdd = func(new Bar { Value = 7 }), 
      withEven = func(new Bar { Value = 12 }); 
    } 
} 

Lưu ý tuy nhiên điều này sẽ được hỗ trợ khác nhau bởi các nhà cung cấp khác nhau. EF có thể không thích nó, ví dụ, ngay cả khi LINQ-to-SQL.

Tùy chọn khác là xây dựng lại cây biểu thức hoàn toàn, sử dụng phản chiếu để tìm các thành viên tương ứng. Phức tạp hơn nhiều.

+0

bạn là thiên tài ... cảm ơn !!! :) – SteveCl

+0

Tôi hy vọng L2EF thích điều này bởi vì tôi đang chuyển đổi một biểu thức từ một giao diện thành lớp cụ thể và trả về kết quả dưới dạng IQueryable ... bạn có nghĩ rằng có cách nào để giảm chi phí không? – IAbstract

+0

+1: điều này giúp tôi đi đúng cách tôi nghĩ. Mặc dù vậy, tôi chắc chắn đã học được điều gì đó mới mẻ. Tôi nhận được một mối quan hệ mất tích từ EF.Tôi sẽ làm việc nhiều hơn một chút trước khi tôi đặt ra một câu hỏi mới. Tôi tự hỏi nếu tôi cần phải đính kèm các bảng thông qua phương pháp EntityCollection ... – IAbstract

2

Không có cách nào ngầm để thực hiện bản dịch. Bạn cần phải quấn đại biểu hiện tại của bạn bên trong một lambda tạo ra một loại mới từ kiểu lập luận:

var translatedPredicate = x => originalPredicate(OtherTypeFromSomeType(x)) 

đâu OtherTypeFromSomeType tạo ra dụ OtherType từ lập luận SomeType.

+0

+1; đánh tôi với nó! –

+2

Câu hỏi là về biểu thức, chứ không phải đại biểu. Bạn không thể sử dụng phương pháp này để gọi một biểu thức con; nó phức tạp hơn. –

+0

Rất tiếc, không đọc kỹ đủ. Dù sao, kỹ thuật về cơ bản là giống nhau, biểu thức chỉ đòi hỏi nhiều công việc hơn (mặc dù về mặt kỹ thuật mã của tôi vẫn hoạt động sau khi biên dịch 'originalPredicate', và sử dụng' Expression <…> 'thay vì' var' ;-)). –

3

Có một cách khác mà tôi đã tìm thấy, điều đó cũng bao gồm việc bao gồm đại biểu ban đầu của bạn.

Func<T, object> ExpressionConversion<U>(Expression<Func<T, U>> expression) 
{ 
    Expression<Func<T, object>> g = obj => expression.Compile().Invoke(obj); 
    return g.Compile(); 
} 
0

tôi đã có vấn đề tương tự như bạn và tôi cố định nó như thế này với EF:

var viewModeValue = dbContext.Model.Select(m => new ViewModel{Field = m.Field}).Where(predicate) //predicate is an Expression<Func<ViewModel, bool>> 

Entity Framework biết làm thế nào để xây dựng các lệnh đúng sql. Chuyển đổi biểu thức phức tạp hơn nhiều, bởi vì nó được xây dựng là không thay đổi và có thể gây ra các hiệu ứng thời gian chạy không mong muốn nếu bạn làm điều gì đó sai, và, trong trường hợp của tôi ít nhất, nó không cần thiết.

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