I need to pass a parameter to a method that requires an Expression<Func<T, bool>>.
How to do I pass an expression that would always return true?
Using obj => true doesn't work because the framework complains at runtime that it cannot determine the memeber type from the True constant.
If you have a function like this
void TakeExpression<T>(Expression<Func<T, bool>> expr)
You should call it this way, specifying the T type :
TakeExpression<int>(_ => true)
It should work.
You need to define the parameter type you are passing:
(object o) => true
Or
(int a) => true
We can achieve the result as follows.
Consider context as your DbContext instance and Entity as your entity class name.
context.Entity.Where(t=> t.EntityID == t.EntityID);
By doing this the where clause will always return true and all the data will be shown.
There are two problems here:
1) If you're passing a predicate such that you always want to return true, then it's not much of a predicate. You may be able to omit whatever call you are trying to make.
2) If you want to just return true, you can simple use a more verbose lambda syntax to get what you want:
sample.AsQueryable().Where((x) => { return true; });
The more verbose syntax allows you to specify closer to an anonymous function while still being an expression.
Related
I've minimised my issue to this:
I have a DbContext with a DbSet<PageBlock> and I get an IQueryable with a simple LINQ "Where" like so:
IQueryable<PageBlock> result = _context.PageBlocks.Where(x => x.PageId == 2);
But if I wrap this line in a method and pass a Func<PageBlock, bool> to the method for the where clause like this:
private IQueryable<PageBlock> GetQueryable(Func<PageBlock, bool> belongsToPage)
{
IQueryable<PageBlock> result = _context.PageBlocks.Where(belongsToPage);
...
}
and call it like this:
var result = GetQueryable(x => x.PageId == 2)
then the .Where now returns an IEnumerable and I get a compile error!? The IDE says I can put an explicit cast on like this:
IQueryable<PageBlock> result =
IQueryable<PageBlock>)_context.PageBlocks.Where(belongsToPage);
but that gives a runtime error
Unable to cast object of type 'WhereEnumerableIterator``1[DAL.Models.PageBlock]' to type 'System.Linq.IQueryable``1[DAL.Models.PageBlock]'.
Why does using the same filter indirectly via the Func param cause my query to return IEnumerable instead of IQueryable ?!
If you want to stay in the IQueryable world then everything in your query has to be executed via EntityFramework in your database. However what the C# compiler sees is that you want to use and call an arbitrary function. The only way it make that work is to enumerate the query so far and call that function on every returned value. It doesn't matter that your specific function could be executed by the database.
If you want to call your method like this var result = GetQueryable(x => x.PageId == 2) you should mimic the signature of Queriable.Where and accept an Expression<Func<TSource,bool>> predicate as your argument.
private IQueryable<PageBlock> GetQueryable(Expression<Func<PageBlock, bool>> belongsToPage)
{
IQueryable<PageBlock> result = _context.PageBlocks.Where(belongsToPage);
...
}
That way the query provider can examin the expression and see if it can be passed to the database
I saw this line of code:
var myFilter= val1 ? (Func<Person, bool>)(person=> true) : (person=> person.IsValid);
What does this part means?:
(Func<Person, bool>)(person=> true)
Then, the myFilter variable is being used to filter some data from a table...
return ctx.Persons.Where(myFilter).ToList();
What happens when val1 is true and the first part of the conditional (Func<Person, bool>)(person=> true) is selected?
The Where method takes a parameter of type Func<T, bool> - this is essentially a function that takes a T (in this case, Person) as a parameter, and returns a bool. The Where method evaluates this function for each object in the source list and filters to only those that result in true.
The delegate person => true defines a method that takes a Person as a parameter and always returns true, regardless of the Person object. When used in a Where clause, this will never filter out anything and returns the original set of items. (The cast to Func<T, bool> is required because of the use of var - the compiler can't determine the type of an anonymous delegate without a hint.)
So this code:
var myFilter = val1 ? (Func<Person, bool>)(person => true) : (person => person.IsValid);
return ctx.Persons.Where(myFilter).ToList();
does the same thing as this:
if (val1)
{
return ctx.Persons.ToList();
}
else
{
return ctx.Persons.Where(person => person.IsValid).ToList();
}
In such case the expression passed to Where returns true always - for any Person passed to it.
For the conditional operator to compile, the two expressions need to have the same type. Lambdas have unique types, so two lambdas don't have the same type. By casting (at least) one of these lambdas to a Func<Person, bool>, the common type of the two expression can be determined to be Func<Person, bool> by implicit conversion of the other lambda to the Func type.
So myFilter is now either the function that always returns true, or if val1 is false, actually does some filtering when used as a Where clause.
I have the following expression:
public Expression<Func<T, bool>> UserAccessCheckExpression<T>(int userId) where T : class
{
return x => (IsAdmin || userId == CurrentUserId || userId == 0);
}
Then I want to apply this filter to several collections (IQueryable) like this one:
return tasks
.Where(t => t.TaskUsers
.Any(x => UserAccessCheckExpression<TaskUser>(x.User) && x.SomeBool == true));
I'm getting the following error while doing so:
Error 40 Cannot implicitly convert type System.Linq.Expressions.Expression<System.Func<TaskUser,bool>> to bool
I can't use workaround with interface inheritance (like TaskUser inherits interface with int UserId property (where T : IHasUserId)) since I want to combine logic.
The problem is that your UserAccessCheckExpression() method is returning an Expression while the Any() method is expecting a boolean.
Now, you can get your code to compile by compiling the Expression and invoking the method (using UserAccessCheckExpression<TaskUser>(x.User).Compile().Invoke(x.User)) but that would obviously fail on runtime because Linq-to-Entities wouldn't be able to translate your Any() to a store query as it no longer contains an Expression.
LinqKit is aiming to solve this problem using its own Invoke extension method that while letting your code compile, will make sure your Expression will get replaced back to its original form using another extension method named AsExpandable() that is extending the entity set.
Try this:
using LinqKit.Extensions;
return tasks
.AsExpandable()
.Where(t => t.TaskUsers.Any(
x => UserAccessCheckExpression<TaskUser>(x.User).Invoke(x)
&& x.SomeBool == true));
More on LinqKit
Yeah, so, you can't do that. There's a difference between an Expression<> and a Func<>. You're trying to use the UserAccessCheckExpression as a func. I'm not sure what you're trying to do, but you can compile it to a func and then use it sorta like you are:
var expr = UserAccessCheckExpression<TaskUser>(x.User);
var func = expr.Compile();
// Later use it like ...
var result = func();
But I expect you're using this with EF or Linq2Sql? That being the case you'll need to rewrite the expression. It can be done by hand (not easy) or, better, use a tool like PredicateBuilder.
I have the following statement.
var search = PredicateBuilder.True<SomeType>();
search.And(f => false);
// Still the "search" variable value is: {f => true}.
At first, I was trying an expression; nothing succeeded, so I tried this "false" instead. No matter what I did, it's still the same. What is happening?
PredicateBuilder methods don't mutate the expression (they couldn't, as expression trees are immutable) - you need to use the return value:
var search = PredicateBuilder.True<SomeType>();
search = search.And(f => false);
I'm trying to DRY out some lambda expressions for security rights. Is it possible to take a lamda expression and apply it to a single entity for true?
Like lets say I have a Person and a DocumentFolder
Expression<Func<Person, bool>> CanSeePerson()
{
return c => !c.IsPrivate;
}
And one for the folder
Expression<Func<DocumentFolder, bool>> CanSeeFolder()
{
return c => !c.IsPrivate && c.Owner.CanSeePerson(); // <- ???
}
How the heck can I use that CanSeePerson() function on a single type to return true and maintain an expression that can be used in linq queries like such
Entities.DocumentFolder.Where(CanSeeFolder());
I know how to use the where on an iqueryable but I can't see how to apply the expression tree to a single value.
This throws the error: Unable to create a constant value of type 'Person'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
Expression<Func<DocumentFolder, bool>> CanSeeFolder()
{
return c => !c.IsPrivate &&_entities.Persons.Where(x => x.Id == c.Owner.Id).Any(CanSeePerson());
}
The difference seems to be based on putting the IQueryable Directly in the statement. This also does NOT work
Expression<Func<DocumentFolder, bool>> CanSeeFolder()
{
return c => !c.IsPrivate &&_entities.Persons.Where(CanSeePerson()).Contains(c.User);
}
but this DOES work
Expression<Func<DocumentFolder, bool>> CanSeeFolder()
{
var canSeePersons = _entities.Persons.Where(CanSeePerson());
return c => !c.IsPrivate && canSeePersons.Contains(c.User);
}
p.s. I know I suck # using this stackoverflow formatting thing lol
The reason why this works is because the CanSeePerson() function cannot be converted and used in an expression. When you put the canSeePersons variable in the function instead you are placing in an iQueryable type which can be used in an expression. Using "var" convolutes it a bit.
You defined a Expression<Func<Person, bool>> that solves your problem. The trick is to simply transform your list of objects to the list you want to filter. It is not always possible, but many times it is. You just have to be a bit creative :-)
When using extension methods you can easily come up with a solution that allows you to do this:
var visibleFolders = Entities.DocumentFolder.WhereCanSeeFolder();
Here is the (completely DRY) solution:
public static class SecurityExtensions
{
public static IQueryable<DocumentFolder> WhereCanSeeFolder(
this IQueryable<DocumentFolder> folders)
{
var visibleOwners = folders.Select(f => f.Owner)
.Where(CanSeePerson);
return
from folder in folders.Where(CanSeeFolder)
where visibleOwners.Contains(folder.Owner)
select folder;
}
private static readonly Expression<Func<DocumentFolder, bool>>
CanSeeFolder = folder => !folder.IsPrivate;
private static readonly Expression<Func<Person, bool>>
CanSeePerson = person => !person.IsPrivate;
}
I hope this helps.
The expression tree is only applied to a single value at a time, logically, within the LINQ expression.
If you're saying you want to apply it in-process later to a single value, you can just use:
// This can be cached
Func<DocumentFolder, bool> canSeeFolderDelegate = CanSeeFolder().Compile();
DocumentFolder folder = ...; // Get the value from somewhere
if (canSeeFolderDelegate(folder))
{
// Yes, you can see that folder
}
Ah, you want to evaluate it for a single entity?
var func = CanSeeFolder().Compile(); // <=== store and re-use this;
// this isn't free
bool canSee = func(obj);
Another approach might be:
bool canSee = Enumerable.Repeat(obj, 1).AsQueryable().Any(CanSeeFolder());
but this is probably still going to do the Compile somewhere in the chain, so you may as well use the more direct code (at the top).
Edit re comments:
To evaluate that at the database, you would need a restriction, for example:
bool canSee = db.Folders.Where(f => f.FolderId == id)
.Where(CanSeeFolder()).Any();
which limits us to the single row, then adds your extra filter.