I want to use expression trees to make filters with entity framework.
So this is my types
public class Type1
{
public string Name { get; set; }
}
public class Type2
{
public IEnumerable<string> Names { get; set; }
}
and this is my specification
public Expression<Func<Entities.Type1, bool>> MyExpression(Type2 filter)
{
//something like where name in (name[0], name[1], ... name[n])
}
I need transform this in something like Sql where in.
How can I do it, and what's the best form?
How can I make Entity Framework understand my arbitrary expression in the way I want?
You can do it simply like this:
public Expression<Func<Type1, bool>> MyExpression(Type2 filter)
{
return x => filter.Names.Contains(x.Name);
}
You can try this:
public Expression<Func<Type1, bool>> MyExpression(Type2 filter)
{
Expression<Func<Type1, bool>> expression = t1 => filter.Names.Contains(t1.Name);
return expression;
}
In this post you can find good explanation why you can convert a lambda expression to an expression tree.
Related
So, I was wondering if it possible to do the next thing in c#:
I have a DB model - let's say it is Car:
public class Car {
public string Id {get;set;}
public string Name {get;set}
}
And a DbSet for this type in someDbContext:
public DbSet<Car> Cars {get;set;}
And also I have a CarDto
public class CarDto {
public string Id {get;set;}
public string Name {get;set}
}
And as result we get something like this:
var select = new Func<CarDto, bool>(car => car.Name == "BMW");
// And somehow use this expression for other type Car
someDbContext.Cars.Where(select);
Maybe there is an approach in which I could map these Funcs like this:
var newFunc = mapper.Map<Func<Car, bool>>(select);
Any thoughts?
If you just want to handle rewriting property accesses, you can use an ExpressionVisitor which looks a bit like this:
public class Program
{
public static void Main()
{
Expression<Func<Car, bool>> expr = x => x.Name == "BMW";
var replaced = ReplaceParameter<CarDto>(expr);
}
private static Expression<Func<T, bool>> ReplaceParameter<T>(LambdaExpression expr)
{
if (expr.Parameters.Count != 1)
throw new ArgumentException("Expected 1 parameter", nameof(expr));
var newParameter = Expression.Parameter(typeof(T), expr.Parameters[0].Name);
var visitor = new ParameterReplaceVisitor()
{
Target = expr.Parameters[0],
Replacement = newParameter,
};
var rewrittenBody = visitor.Visit(expr.Body);
return Expression.Lambda<Func<T, bool>>(rewrittenBody, newParameter);
}
}
public class ParameterReplaceVisitor : ExpressionVisitor
{
public ParameterExpression Target { get; set; }
public ParameterExpression Replacement { get; set; }
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression == this.Target)
{
// Try and find a property with the same name on the target type
var members = this.Replacement.Type.GetMember(node.Member.Name, node.Member.MemberType, BindingFlags.Public | BindingFlags.Instance);
if (members.Length != 1)
{
throw new ArgumentException($"Unable to find a single member {node.Member.Name} of type {node.Member.MemberType} on {this.Target.Type}");
}
return Expression.MakeMemberAccess(this.Replacement, members[0]);
}
return base.VisitMember(node);
}
}
We need to deconstruct the LambdaExpression into its body and parameters. We need to create a new parameter which has the correct type, and replace all usages of the old parameter with the new one. This is where the visitor comes in: whenever it sees you access a member on the old parameter, it tries to find the corresponding member on the new parameter, and access that instead.
We then construct a new LambdaExpression, using the rewritten body and the new parameter.
You have a whole bunch of options:
Derive your Dto class from the context class. That way you can use polymorphism as normal.
Extract an interface and implement it in both your Dto and context classes. Same as above then, use polymorphism.
Use duck-typing. In C#, that's done with the dynamic keyword. You lose Intellisense and compile-time error checking, but your code will work.
Reflection. It's a lot of code, it's slow, it's practically a much worse version of #3, but you can cobble it together if you really try.
Something like Automapper will help you map your context to your Dto piece-wise, but it won't help you translate your lambda function filters.
Editing this question in the hope to make it clearer.
We have entity framework code first setup. I've simplified two classes for the purposes of example, in reality there are around 10+ more classes similar to the 'Record', where Item is a navigational property/foreign key.
Item class:
public class Item
{
public int Id { get; set; }
public int AccountId { get; set; }
public List<UserItemMapping> UserItemMappings { get; set; }
public List<GroupItemMapping> GroupItemMappings { get; set; }
}
Record class:
public class Record
{
public int ItemId { get; set; }
public Item Item { get; set; }
}
this.User is an injected user object into each repo and is contained on the repository base.
We have an Item repository with the following code:
var items = this.GetAll()
.Where(i => i.AccountId == this.User.AccountId);
I created the follow expression on the repository base to easily filter on that (in the hope of re-use). We cannot use static extension methods due to how LINQ to entities works (System.NotSupportedException "LINQ to Entities does not recognize the method X and this method cannot be translated into a store expression.").
protected Expression<Func<Item, bool>> ItemIsOnAccount()
{
return item => item.AccountId == this.User.AccountId;
}
I have solved the case of the above, by doing this:
var items = this.GetAll().Where(this.ItemIsOnAccount());
We have additional filtering based on user permissions within that account (again, another case where I do not want to repeat this code in every repo we have):
protected Expression<Func<Item, bool>> SubUserCanAccessItem()
{
return item => this.User.AllowAllItems
|| item.UserItemMappings.Any(d => d.UserId.Value == this.User.Id)
|| item.GroupItemMappings.Any(vm =>
vm.Group.GroupUserMappings
.Any(um => um.UserId == this.User.Id));
}
Which I am able to use as follows:
var items = this.GetAll().Where(this.SubUserCanAccessItem());
However, what we also need, in the Record repository is a way to solve the following:
var records = this.GetAll()
.Where(i => i.Item.AccountId == this.User.AccountId);
Because Item is a single navigational property, I do not know how to apply the expressions I have created to this object.
I want to reuse the expression I created in the repo base on all of these other repos, so that my 'permission based' code is all in the same place, but I cannot simply throw it in because the Where clause in this case is of Expression< Func < Record,bool >>.
Creating an interface with a method of:
Item GetItem();
on it and putting it on the Record class does not work because of LINQ to entities.
I cannot also create a base abstract class and inherit from it, because there could be other objects than Item that need to be filtered on. For instance a Record could also have a 'Thing' on it that has permission logic. Not all objects will require to be filtered by 'Item' and 'Thing', some by only one, some by another, some by both:
var items = this.GetAll()
.Where(this.ItemIsOnAccount())
.Where(this.ThingIsOnAccount());
var itemType2s = this.GetAll().Where(this.ThingIsOnAccount());
var itemType3s = this.GetAll().Where(this.ItemIsOnAccount());
Due to this having a single parent class would not work.
Is there a way in which I can reuse the expressions I have already created, or at least create an expression/modify the originals to work across the board within the OTHER repos that of course return their own objects in a GetAll, but all have a navigation property to Item? How would I need to modify the other repos to work with these?
Thanks
The first step for expression reusability is to move the expressions to a common static class. Since in your case they are tied to User, I would make them User extension methods (but note that they will return expressions):
public static partial class UserFilters
{
public static Expression<Func<Item, bool>> OwnsItem(this User user)
=> item => item.AccountId == user.AccountId;
public static Expression<Func<Item, bool>> CanAccessItem(this User user)
{
if (user.AllowAllItems) return item => true;
return item => item.UserItemMappings.Any(d => d.UserId.Value == user.Id) ||
item.GroupItemMappings.Any(vm => vm.Group.GroupUserMappings.Any(um => um.UserId == user.Id));
}
}
Now the Item repository would use
var items = this.GetAll().Where(this.User.OwnsItem());
or
var items = this.GetAll().Where(this.User.CanAccessItem());
In order to be reusable for entities having Item reference, you would need a small helper utility for composing lambda expressions from other lambda expressions, similar to Convert Linq expression "obj => obj.Prop" into "parent => parent.obj.Prop".
It's possible to implement it with Expression.Invoke, but since not all query providers support for invocation expressions (EF6 doesn't for sure, EF Core does), as usual we'll use a custom expression visitor for replacing a lambda parameter expression with another arbitrary expression:
public static partial class ExpressionUtils
{
public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
=> new ParameterReplacer { Source = source, Target = target }.Visit(expression);
class ParameterReplacer : ExpressionVisitor
{
public ParameterExpression Source;
public Expression Target;
protected override Expression VisitParameter(ParameterExpression node)
=> node == Source ? Target : node;
}
}
And the two composing functions are as follows (I don't like the name Compose, so sometimes I use the name Map, sometimes Select, Bind, Transform etc., but functionally they do the same. In this case I'm using Apply and ApplyTo, with the only difference being the transformation direction):
public static partial class ExpressionUtils
{
public static Expression<Func<TOuter, TResult>> Apply<TOuter, TInner, TResult>(this Expression<Func<TOuter, TInner>> outer, Expression<Func<TInner, TResult>> inner)
=> Expression.Lambda<Func<TOuter, TResult>>(inner.Body.ReplaceParameter(inner.Parameters[0], outer.Body), outer.Parameters);
public static Expression<Func<TOuter, TResult>> ApplyTo<TOuter, TInner, TResult>(this Expression<Func<TInner, TResult>> inner, Expression<Func<TOuter, TInner>> outer)
=> outer.Apply(inner);
}
(Nothing special there, code provided for completeness)
Now you could reuse the original filters by "applying" them to a expression which selects Item property from another entity:
public static partial class UserFilters
{
public static Expression<Func<T, bool>> Owns<T>(this User user, Expression<Func<T, Item>> item)
=> user.OwnsItem().ApplyTo(item);
public static Expression<Func<T, bool>> CanAccess<T>(this User user, Expression<Func<T, Item>> item)
=> user.CanAccessItem().ApplyTo(item);
}
and add the following to the entity repository (in this case, Record repository):
static Expression<Func<Record, Item>> RecordItem => entity => entity.Item;
which would allow you to use there
var records = this.GetAll().Where(this.User.Owns(RecordItem));
or
var records = this.GetAll().Where(this.User.CanAccess(RecordItem));
This should be enough to satisfy your requirements.
You can go further and define an interface like this
public interface IHasItem
{
Item Item { get; set; }
}
and let the entities implement it
public class Record : IHasItem // <--
{
// Same as in the example - IHasItem.Item is auto implemented
// ...
}
then add additional helpers like this
public static partial class UserFilters
{
public static Expression<Func<T, Item>> GetItem<T>() where T : class, IHasItem
=> entity => entity.Item;
public static Expression<Func<T, bool>> OwnsItem<T>(this User user) where T : class, IHasItem
=> user.Owns(GetItem<T>());
public static Expression<Func<T, bool>> CanAccessItem<T>(this User user) where T : class, IHasItem
=> user.CanAccess(GetItem<T>());
}
which would allow you omit the RecordItem expression in the repository and use this instead
var records = this.GetAll().Where(this.User.OwnsItem<Record>());
or
var records = this.GetAll().Where(this.User.CanAccessItem<Record>());
Not sure if it gives you a better readability, but is an option, and syntactically is closer to Item methods.
For Thing etc. just add similar UserFilters methods.
As a bonus, you can go even further and add the usual PredicateBuilder methods And and Or
public static partial class ExpressionUtils
{
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
=> Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left.Body,
right.Body.ReplaceParameter(right.Parameters[0], left.Parameters[0])), left.Parameters);
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
=> Expression.Lambda<Func<T, bool>>(Expression.OrElse(left.Body,
right.Body.ReplaceParameter(right.Parameters[0], left.Parameters[0])), left.Parameters);
}
so you could use something like this if needed
var items = this.GetAll().Where(this.User.OwnsItem().Or(this.User.CanAccessItem()));
in the Item repository, or
var records = this.GetAll().Where(this.User.OwnsItem<Record>().Or(this.User.CanAccessItem<Record>()));
in the Record repository.
I can't really tell if this could work in your case, depends on how your entities might be setup, but one thing you can try is to have an interface like IHasItemProperty with a GetItem() method and have the entities where you want to use this implement that interface. Something like this :
public interface IHasItemProperty {
Item GetItem();
}
public class Item: IHasItemProperty {
public Item GetItem() {
return this;
}
public int UserId {get; set;}
}
public class Record: IHasItemProperty {
public Item item{get;set;}
public Item GetItem() {
return this.item;
}
}
public class Repo
{
protected Expression<Func<T, bool>> ItemIsOnAccount<T>() where T: IHasItemProperty
{
return entity => entity.GetItem().UserId == 5;
}
}
I have used an int just to make things simpler.
You should be able to do this with .AsQueryable().
class Account
{
public IEnumerable<User> Users { get; set; }
public User SingleUser { get; set; }
static void Query()
{
IQueryable<Account> accounts = new Account[0].AsQueryable();
Expression<Func<User, bool>> userExpression = x => x.Selected;
Expression<Func<Account, bool>> accountAndUsersExpression =
x => x.Users.AsQueryable().Where(userExpression).Any();
var resultWithUsers = accounts.Where(accountAndUsersExpression);
Expression<Func<Account, bool>> accountAndSingleUserExpression =
x => new[] { x.SingleUser }.AsQueryable().Where(userExpression).Any();
var resultWithSingleUser = accounts.Where(accountAndSingleUserExpression);
}
}
class User
{
public bool Selected { get; set; }
}
You should only use sql (or your database like) items for the predicate. If you put this.User.AccountId into your lambda, that does not exists at database and can't be parsed by it, that's the source of your error message.
I have built a predicate by the Address model (Expression<Func<Address, bool>> addressPred). Now i want to combine this with a predicate of the Person model (Expression<Func<Person, bool>> personPred). Example of the models are:
public class Person
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string StreetName { get; set; }
}
If I do something like
addressPred = addressPred.And(a => a.StreetName == "Foo bar");
and then combine it with the personPred, the combined predicate will have a statement equalent to
combinedPred = combinedPred.And(a => a.Address.StreetName == "Foo bar");
The combinedPredicate is of type Person.
How can I achive this?
Edit:
In reality the models are alot bigger and are shortened for simplicity's sake. What I ultimately want to achive is to build the Address predicate once, then build a predicate for Person with its own conditions and then combine it into a predicate where the Address-part of the Person predicate comes from the Address predicate (Address is a property of Person). The reason I want to do it this way is because Address may have alot of conditions, and I want to use it as a part of other predicates (Person, later also Company, Customer etc) before making a db-call (to Person, Company, Customer etc)
Also the combinedPred line of code was only to show what the equalent statement of the combinedPred would be like coming from Address predicate.
The situation is that the built Expression<Func<Address, bool>> addressPred has an address as ParameterExpression and it is requred to apply the expression to a MemberExpression. So I can suggest to replace the ParameterExpression with the MemberExpression like that:
var personParameter = Expression.Parameter(typeof(Person), "person");
var addressProperty = Expression.PropertyOrField(personParameter, "Address");
var combined = new ReplaceVisitor<Address>(addressProperty).Visit(addressPred.Body);
var result = Expression.Lambda<Func<Person, bool>>(combined, personParameter);
Where:
public class ReplaceVisitor<T> : ExpressionVisitor
{
private readonly MemberExpression _replacement;
public ReplaceVisitor(MemberExpression replacement)
{
_replacement = replacement;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node.Type.IsAssignableFrom(typeof(T))
? _replacement : base.VisitParameter(node);
}
}
As stated here EntityFramework (at least in version 6) does not support user types comparison (and thus, entities comparison) which is not practical for an ORM.
I have a scenario where I have a lot of code that does entities comparison that should be translated to SQL.
All my entities have an Id field of type int.
class Entity
{
public int Id { get; set; }
}
For queries where I want to compare entities in a Where clause, I would like to be able the compiler to detect if trying to perform an invalid comparison.
Considere the following classes :
class SomeEntity : Entity
{
public RelationEntity_Id int{ get; set; }
public RelationEntity Relation { get; set; }
}
class RelationEntity : Entity
{
}
With the following syntax there is such a check on the types:
public IQueryable<SomeEntity> SearchByRelation(RelationEntity relation)
{
return CreateQueryable().Where(e => s.Relation == relation);
}
With the following one, we are only comparing int and this could be error prone :
public IQueryable<SomeEntity> SearchByRelation(RelationEntity relation)
{
return CreateQueryable().Where(e => s.Relation.Id == relation.Id);
}
Because EntityFramework needs to be told how the comparison on objects should be done, I'm looking for a way create a generic Expression returning an expression Comparing the Id of a SomeEntity with the Id of a RelationEntity.
Something like this :
public IQueryable<SomeEntity> SearchByRelation(RelationEntity relation)
{
return CreateQueryable().Where(e => AreEquals(s.Relation, relation));
}
AreEquals would be adapting the Expression Tree for the SQL generated correctly comparing on entity Ids.
I have found this post which seems to be a good start, but I can't get it to append the '.Id' part of the Expression.
Any idea of how I could achieve this, or what could be the good way to go ?
Here you go.
The helper function (inside some static class):
public static IQueryable<T> WhereEquals<T>(this IQueryable<T> source, T target)
where T : Entity
{
var item = Expression.Parameter(typeof(T), "item");
var body = Expression.Equal(
Expression.Property(item, "Id"),
Expression.Property(Expression.Constant(target), "Id"));
var predicate = Expression.Lambda<Func<T, bool>>(body, item);
return source.Where(predicate);
}
and the usage:
public IQueryable<SomeEntity> SearchByRelation(RelationEntity relation)
{
return CreateQueryable().WhereEquals(relation);
}
I'm trying to build a generic method that EF4.1 to look in both the Database and the Local memory for a particular row in a table that matches a particular criteria.
So far, this is what I have this.
This is the caller.
dbEntities.MyTables.LocalAndDb(delegate(MyTable s)
{ return s.Description.Contains("test"); });
This is LocalAndDb
public static object LocalAndDb<T>(this DbSet<T> myTable, Func<T, bool> function) where T : class
{
// look in local
var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault()
// if not exist, look in the database
if (item == null)
{
Expression<Func<T, bool>> predicate = (u) => function(u);
item = myTable.Where(predicate).FirstOrDefault();
}
return item;
}
The problem is with this line.
item = myTable.Where(predicate).FirstOrDefault();
When it calls the database, it throws this error.
"The LINQ expression node type 'Invoke' is not supported in LINQ to Entities."
I imagine it's because I'm passing in an anonymous method and it doesn't know how to turn this into SQL. I thought converting it to an Expression object would do the trick but it's still not working for me.
What do I need to do to make a anonymous method become something that LINQ can turn into SQL?
To make this work, you need to pass the lambda expression to LocalAndDb as an expression tree (so that LINQ to Entities can analyze the code and translate it to SQL):
public static object LocalAndDb<T>(this DbSet<T> myTable,
Expression<Func<T, bool>> expr) where T : class {
// ...
if (item == null) {
item = myTable.Where(expr).FirstOrDefault();
}
return item;
}
Then, of course, the problem is that you cannot execute the expression tree when checking the in-memory data. One way to solve this is to use the Compile method of Expression<T>, but that will be a bit inefficient (depending on your scenario).
Another option is to just pass the condition as both function and expression tree:
public static object LocalAndDb<T>(this DbSet<T> myTable,
Func<T, boo> function, Expression<Func<T, bool>> expr) where T : class {
var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault();
if (item == null) {
item = myTable.Where(expr).FirstOrDefault();
}
return item;
}
table.LocalAndDb(t => t.Foo > 10, t => t.Foo > 10);
This is a bit ugly, but it doesn't require inefficient compilation at runtime. If you want a slightly more sophisticated solution, then you can define your own type to keep pre-compiled functions:
class Precompiled<T1, T2> {
public Precompiled(Expression<Func<T1, T2>> expr) {
this.Expression = expr;
this.Function = expr.Compile();
}
public Expression<Func<T1,T2>> Expression { get; private set; }
public Func<T1,T2> Function { get; private set; }
}