2015-11-19 11 views
5

Tôi nhận được lỗi sauKết hợp nhiều biểu thức cây

Tham số 'p' không bị ràng buộc trong LINQ to Entities định biểu thức truy vấn.

Tôi hiểu vấn đề (giống trường hợp của ParameterExpression nên được sử dụng với tất cả các biểu thức trong cây) và đã cố gắng sử dụng các giải pháp tôi đã tìm thấy trực tuyến nhưng không có may mắn.

Đây là phương pháp của tôi

private void SeedEntity<TEntity>(DatabaseContext context, ref TEntity entity, params Expression<Func<TEntity, object>>[] identifierExpressions) where TEntity : class 
{ 
    Expression<Func<TEntity, bool>> allExpresions = null; 

    var parameters = identifierExpressions.SelectMany(x => x.Parameters).GroupBy(x => x.Name).Select(p => p.First()).ToList(); 

    foreach (Expression<Func<TEntity, object>> identifierExpression in identifierExpressions) 
    { 
     Func<TEntity, object> vv = identifierExpression.Compile(); 
     object constant = vv(entity); 

     ConstantExpression constExp = Expression.Constant(constant, typeof(object)); 
     BinaryExpression equalExpression1 = Expression.Equal(identifierExpression.Body, constExp); 
     Expression<Func<TEntity, bool>> equalExpression2 = Expression.Lambda<Func<TEntity, bool>>(equalExpression1, parameters); 

     if (allExpresions == null) 
     { 
      allExpresions = equalExpression2; 
     } 
     else 
     { 
      BinaryExpression bin = Expression.And(allExpresions.Body, equalExpression2.Body); 
      allExpresions = Expression.Lambda<Func<TEntity, bool>>(bin, parameters); 
     } 
    } 

    TEntity existingEntity = null; 
    if (allExpresions != null) 
    { 
     existingEntity = context.Set<TEntity>().FirstOrDefault(allExpresions); 
    } 

    if (existingEntity == null) 
    { 
     context.Set<TEntity>().Add(entity); 
    } 
    else 
    { 
     entity = existingEntity; 
    } 
} 

Nó tạo ra một biểu hiện cho việc tra cứu của một thực thể dựa trên một số tài sản.

Nó hoạt động tốt cho một biểu thức duy nhất, lỗi chỉ xảy ra khi truyền trong nhiều.

gọi là như thế này:

SeedEntity(context, ref e, p=> p.Name);//Works 
SeedEntity(context, ref e, p=> p.Name, p=> p.Age);//Fails 

Nó tạo ra một cái gì đó tương tự như tôi thực hiện như sau:

context.Set<TEntity>().FirstOrDefault(p=>p.Name == e.Name && p.Age == e.Age); 

Thay e.Name & & e.Age với một ConstantExpression

Bạn có thể xem trong phương pháp trên, tôi lấy tất cả các thông số duy nhất và lưu trữ chúng trong parameters tại p, sau đó sử dụng cùng một biến trong suốt.Đây là sự bắt đầu, nhưng sau đó tôi cần phải thay thế các trường hợp của tham số trong mỗi Expression<Func<TEntity, bool>> được chuyển thành mảng params, đây là nơi tôi đang thất bại.

Tôi đã thử liệt kê các từ ngữ và sử dụng các phương pháp .Update() qua trong params

Tôi cũng đã thử một giải pháp sử dụng các ExpressionVisitor

public class ExpressionSubstitute : ExpressionVisitor 
{ 
    public readonly Expression from, to; 
    public ExpressionSubstitute(Expression from, Expression to) 
    { 
     this.from = from; 
     this.to = to; 
    } 
    public override Expression Visit(Expression node) 
    { 
     if (node == from) return to; 
     return base.Visit(node); 
    } 
} 

public static class ExpressionSubstituteExtentions 
{ 
    public static Expression<Func<TEntity, TReturnType>> RewireLambdaExpression<TEntity, TReturnType>(Expression<Func<TEntity, TReturnType>> expression, ParameterExpression newLambdaParameter) 
    { 
     var newExp = new ExpressionSubstitute(expression.Parameters.Single(), newLambdaParameter).Visit(expression); 
     return (Expression<Func<TEntity, TReturnType>>)newExp; 
    } 
} 
+0

Chỉ cần suy nghĩ nhanh, bạn đã thử sử dụng một chữ cái khác cho tham số thứ hai chưa? (tức là p => p.Name, f => f.Age) –

+0

Cảm ơn bạn đã nhập, thao tác này sẽ không bao giờ hoạt động, vì bạn chỉ có một tham số nhưng bạn chỉ có một tham số. Nó sẽ ném số thông số không chính xác được cung cấp cho lambda –

+2

Thay vì kết hợp các truy vấn, tại sao không áp dụng chúng liên tục? 'results =/* Toàn bộ * /; foreach (expression) {results = results.Where (expression)} '? Vì EF sử dụng 'IQueryable', khung công tác sẽ hoãn thực thi cho đến khi cần thiết, sau đó kết hợp tất cả các biến vị ngữ thành một truy vấn duy nhất cho SQL. – Basic

Trả lời

4

Bạn đang thực sự gần gũi. Tôi không thấy điểm của biến số parameters của bạn. Nhóm chúng theo tên là một sai lầm. Tại sao không chỉ truyền các tham số từ biểu thức? Sau đó truy cập nếu cần thiết. Mã khách truy cập của bạn là tốt.

private static void SeedEntity<TEntity>(DbContext context, ref TEntity entity, params Expression<Func<TEntity, object>>[] identifierExpressions) 
     where TEntity : class 
    { 
     Expression<Func<TEntity, bool>> allExpresions = null; 

     foreach (Expression<Func<TEntity, object>> identifierExpression in identifierExpressions) 
     { 
      Func<TEntity, object> vv = identifierExpression.Compile(); 
      object constant = vv(entity); 

      ConstantExpression constExp = Expression.Constant(constant, typeof(object)); 
      BinaryExpression equalExpression1 = Expression.Equal(identifierExpression.Body, constExp); 
      Expression<Func<TEntity, bool>> equalExpression2 = Expression.Lambda<Func<TEntity, bool>>(equalExpression1, identifierExpression.Parameters); 

      if (allExpresions == null) 
      { 
       allExpresions = equalExpression2; 
      } 
      else 
      { 
       var visitor = new ExpressionSubstitute(allExpresions.Parameters[0], identifierExpression.Parameters[0]); 
       var modifiedAll = (Expression<Func<TEntity,bool>>)visitor.Visit(allExpresions); 
       BinaryExpression bin = Expression.And(modifiedAll.Body, equalExpression2.Body); 
       allExpresions = Expression.Lambda<Func<TEntity, bool>>(bin, identifierExpression.Parameters); 
      } 
     } 

     TEntity existingEntity = null; 
     if (allExpresions != null) 
     { 
      existingEntity = context.Set<TEntity>().FirstOrDefault(allExpresions); 
     } 

     if (existingEntity == null) 
     { 
      context.Set<TEntity>().Add(entity); 
     } 
     else 
     { 
      entity = existingEntity; 
     } 
    } 
+1

Tôi nắm lấy quyền truy cập duy nhất mà tôi có thể sử dụng lại trường hợp đó bằng cách thay thế các tham số (không phải trong ví dụ trên). Giải pháp của bạn hoạt động, cảm ơn bạn rất nhiều. Tôi thấy bây giờ tôi đã đi sai –

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