Unable to create filter
tbrettallen opened this issue · 9 comments
I have the following
builder.Filter("ChmActivity_Ministry",
(Ministry m, DbSet<MinistryUser> ministryUsers, int userId) => ministryUsers.Any(mu => mu.UserId == AuthenticatedUser.Id && mu.MinistryId == m.MinistryId),
(ChmActivityContext db) => db.MinistryUsers,
() => AuthenticatedUser?.Id ?? 0);
I'm attempting to pass two arguments to the expression. One for the ministry users DbSet, one for the currently authenticated user.
The compile error says "Delegate 'Expression<Func<Ministry, DbSetMinistryUser>, bool>>' does not take 3 arguments"
Where is the bool coming from, and why am I unable to add multiple filter parameters in this scenario?
Hello @tbrettallen ,
The bool
(the last argument) is the return type in the predicate.
By example,
() => true
is aFunc<bool>
(int x) => true
is aFunc<int, bool>
The problem in your statement in this line () => AuthenticatedUser?.Id ?? 0);
, it seem overload either require all parameters to have no context, or a context.
Try to change it with the following expression and I believe it will work:
builder.Filter("ChmActivity_Ministry",
(Ministry m, DbSet<MinistryUser> ministryUsers, int userId) => ministryUsers.Any(mu => mu.UserId == AuthenticatedUser.Id && mu.MinistryId == m.MinistryId),
(ChmActivityContext db) => db.MinistryUsers,
(ChmActivityContext db) => AuthenticatedUser?.Id ?? 0);
Let me know if that worked successfully.
Best Regards,
Jonathan
Hello @tbrettallen ,
I will close this issue, if you have more question please reopen it.
Best Regards,
Jonathan
That appears to have worked, thank you!
Great ;)
Thank you for letting me know.
New problem has surfaced using this method. I have the following
builder.Filter("ChmPeople_Note",
(Note note, DbSet<UserDataPrivilege> dataPrivileges, int userId) => dataPrivileges.Where(dp => dp.SecurityTypeId == SecurityType.IndividualNote).Any(dp => dp.UserId == userId && dp.DataId == note.NoteTypeId),
(ChmPeopleContext db) => db.UserDataPrivileges,
(ChmPeopleContext db) => AuthenticatedUser?.Id ?? 0);
And am getting this error: "Unhandled Method of Where in LambdaToDbExpressionVisitor.VisitMethodCall"
Any ideas what this could be?
Update, I tried the following and it resolved that error:
builder.Filter("ChmPeople_Note",
(Note note, DbSet<UserDataPrivilege> dataPrivileges, int userId) => dataPrivileges.Any(dp => dp.SecurityTypeId == SecurityType.IndividualNote && dp.UserId == userId && dp.DataId == note.NoteTypeId),
(ChmPeopleContext db) => db.UserDataPrivileges,
(ChmPeopleContext db) => AuthenticatedUser?.Id ?? 0);
(Removed where, stuffed it in the Any)
Now I get: "Unable to map parameter of type UserDataPrivilege to TypeUsage. Found 0 matching types"
You can't pass in a DbSet as a parameter - only basic types. The library (and EF for that matter) will have no idea how to relate your Note entity with that random DbSet to make the join.
Assuming your Note entity is actually related to UserDataPrivileges, you should be able to write the filter like this:
builder.Filter("ChmPeople_Note",
(Note note, int userId) => note.DataPrivileges.Any(dp => dp.SecurityTypeId == SecurityType.IndividualNote && dp.UserId == userId),
(ChmPeopleContext db) => AuthenticatedUser?.Id ?? 0);
It unfortunately is not, it's a view I'm trying to pull in.
The issue we're having is .Contains in EF is causing some serious performance bottle necks, which we were using in dynamic filters for permissions enforcement.
So we're trying to switch to using a Any() for a view, since EF compiles that differently. Hence the attempt to use DbSet.
Can I pass in an IQueryable?
No, the library will not know how to relate that to the entity either. It needs to be able to translate the parameter into something that can be compared to a column value in a sql statement. So it must be a "value" not a "set".
Unless you can find a way to make that FK link in your model (and write the filter as I suggested), I don't think this can be handled in a filter.