EntityFramework.DynamicFilters icon indicating copy to clipboard operation
EntityFramework.DynamicFilters copied to clipboard

Having problem when applying filter on child collection

Open elferone opened this issue 8 years ago • 7 comments

I have a class Project that contains a collection of ProjectResourceMembers.

My filter is defined like this:

//Security
                modelBuilder.Filter("ProjectFilter",
                    (Project p, string resourceCode) => (p.ProjectResourceMembers.Any(x => x.ResourceCode.ToLower() == GetResourceCodeFromPrincipal(Thread.CurrentPrincipal)) 
                    && p.IsConfidential == true) || p.IsConfidential == false,
                    () => GetResourceCodeFromPrincipal(Thread.CurrentPrincipal));

                modelBuilder.EnableFilter("ProjectFilter", () => !string.IsNullOrEmpty(GetResourceCodeFromPrincipal(Thread.CurrentPrincipal)));

However, when I query the context (via OData), I get this exception:

variable 'x' of type 'DataHub.Provider.Models.Atomic.ProjectResourceMember' referenced from scope '', but it is not defined

The error seems to be related to x.ResourceCode.ToLower()... Any idea what the error might be?

elferone avatar Oct 30 '17 15:10 elferone

Hello @elferone ,

I'm not exactly sure yet what's the error but something for sure doesn't work in this expression.

The filter modifies the SQL queries that will be sent to the database.

However, this part: x => x.ResourceCode.ToLower() == GetResourceCodeFromPrincipal(Thread.CurrentPrincipal)

Cannot be translated to a SQL query because of the method GetResourceCodeFromPrincipal

I believe you can already use the variable resourceCode instead.

Can you try to fix the filter expression and tell us if you still have the same issue?

Best Regards,

Jonathan

JonathanMagnan avatar Oct 30 '17 18:10 JonathanMagnan

I have fixed the expression to:

//Security
                modelBuilder.Filter("ProjectFilter",
                    (Project p, string resourceCode) => (p.ProjectResourceMembers.Any(x => x.ResourceCode.ToLower() == resourceCode) 
                    && p.IsConfidential == true) || p.IsConfidential == false,
                    () => Thread.CurrentPrincipal.Identity.Name.ToLower());

The error still happens when I use the ToLower() function on x.ResourceCode:

x => x.ResourceCode.ToLower()

elferone avatar Oct 31 '17 11:10 elferone

Hello @elferone ,

Thank you, I will try to create a similar filter on my side and see if something is missing for the ToLower method.

Best Regards,

Jonathan

JonathanMagnan avatar Oct 31 '17 13:10 JonathanMagnan

.ToLower() is not supported. And I don't see an obvious way to map that C# function to the database function. It does not seem to be exposed in DbExpressionBuilder (we are limited in this library to what EF has decided to expose to us).

There are some other custom functions being handled in LambdaToDbExpressionVisitor.VisitMethodCall() - that would probably be the right place to add support if it's possible to map it.

jcachat avatar Oct 31 '17 14:10 jcachat

Thank you @jcachat for letting me know.

I believe there is certainly a way since a DbExpression must be returned but I'm not sure either how doing it yet.

Best Regards,

Jonathan

JonathanMagnan avatar Oct 31 '17 14:10 JonathanMagnan

Hello @elferone ,

The v3.0.0 has been released.

The support for ToLower and ToUpper for basic scenario should now work.

Let me know if you run into another issue.

@jcachat , using your code made this request pretty easy ;) I'm not sure if that handle all scenarios but that will at least handle some basic scenario,

Here is the code added

case "ToLower":
	expression = MapSimpleExpression(node, EdmFunctions.ToLower);
	break;

private Expression MapSimpleExpression(MethodCallExpression node, Func<DbExpression, DbFunctionExpression> dbExpressionFactory)
{
	var expression = base.VisitMethodCall(node) as MethodCallExpression;

	DbExpression srcExpression = GetDbExpressionForExpression(expression.Object);
	var dbExpression = dbExpressionFactory(srcExpression);
	MapExpressionToDbExpression(expression, dbExpression);
	return expression;
}

Best Regards,

Jonathan

JonathanMagnan avatar Nov 01 '17 01:11 JonathanMagnan

Works like a charm. Good job and thanks again!

elferone avatar Nov 01 '17 17:11 elferone