You get an exception because Queryable.Where expects an expression that can be translated into SQL, and ActiveRecords cannot be translated into SQL.
What you need to do is update the expression to deploy the ActiveRecords call to the .Where(e => e.RecordStatusTypeId != (int)RecordStatusTypes.Deleted call .Where(e => e.RecordStatusTypeId != (int)RecordStatusTypes.Deleted ).
I am going to provide a project for a solution that works. This is very specific to the example you provided. You should probably work on this to make it general.
The following visitor expression will basically change the ActiveRecords call to the Where call with the corresponding expression as an argument:
public class MyVisitor : ExpressionVisitor { protected override Expression VisitMethodCall(MethodCallExpression m) { if (m.Method.Name == "ActiveRecords") { var entityType = m.Method.GetGenericArguments()[0]; var whereMethod = genericWhereMethod.MakeGenericMethod(entityType); var param = Expression.Parameter(entityType); var expressionToPassToWhere = Expression.NotEqual( Expression.Property(param, "RecordStatusTypeId"), Expression.Constant((int)RecordStatusTypes.Deleted)); Expression newExpression = Expression.Call( whereMethod, m.Arguments[0], Expression.Lambda( typeof(Func<,>).MakeGenericType(entityType, typeof(bool)), expressionToPassToWhere, param)); return newExpression; } return base.VisitMethodCall(m); }
Then you can create a special WhereSpecial method to view the expression before passing it to the real Where Queryable method:
public static class ExtentionMethods { public static IQueryable<T> WhereSpecial<T>(this IQueryable<T> queryable, Expression<Func<T,bool>> expression ) { MyVisitor visitor = new MyVisitor(); var newBody = visitor.Visit(expression.Body); expression = expression.Update(newBody, expression.Parameters); return queryable.Where(expression); } }
And then you can use it as follows:
var result = MyDbContext.Entities.WhereSpecial(e => e.RelatedEntity.ActiveRecords().Any());
source share