How to invoke Expression<Func<Entity, bool>> against a collection - c#

I have an interface that defines a repository from the Repository pattern:
interface IRepository
{
List<Customer> GetAllCustomers(Expression<Func<Customer, bool>> expression);
}
I've implemented it against Entity Framework:
class EntityFrameworkRepository
{
public List<Customer> GetAllCustomers(Expression<Func<Customer, bool>> expression)
{
return DBContext.Customers.Where(expression).ToList();
}
}
That seems to work well, it allows me to do something like:
var customers = entityFrameworkRepository.Where(
customer => String.IsNullOrEmpty(customer.PhoneNumber)
);
Now I'd like to have an InMemoryRepository for testing and demo purposes. I attempted to create one:
class InMemoryRepository
{
Dictionary<int, Customer> Customers {get; set;} = new Dictionary<int, Customer>();
public List<Customer> GetAllCustomers(Expression<Func<Customer, bool>> expression)
{
//what do I put here?
}
}
As you can see in the above code, I'm stumped on what to do for InMemoryRepository.GetAllCustomers implementation. What should I do there to filter the Customers by the provided expression and return the results?
I tried:
return Customers.Where(expression));
But obviously it's expecting a Func<KeyValuePair<int, Customer>, bool> so I get a compilation error:
Error CS1929 'Dictionary' does not contain a definition for 'Where' and the best extension method overload 'Queryable.Where(IQueryable, Expression>)' requires a receiver of type 'IQueryable' DataAccess.InMemory

Try .AsQueryable() method:
return Customers.Values.AsQueryable().Where(expression);

Example
Expression<Func<Products, bool>> expresionFinal = p => p.Active;
if (mydate.HasValue)
{
Expression<Func<Products, bool>> expresionDate = p => (EntityFunctions.TruncateTime(c.CreatedDate) <= mydate);
expresionFinal = PredicateBuilder.And(expresionFinal, expresionDate );
}
IQueryable<T> query = dbSet;
query = query.Where(expresionFinal);

Related

Map Expression<Func<Dto, bool>> to Expression<Func<Entity, bool>> using AutoMapper

I have a repository->service architecture that uses a LINQ expression to filter many data. Repositories work with entities and Services with the DTOs. At the moment, I use Automapper to map entity to dto and vice-versa. In the repository, I have a method that accepts an Expression> LINQ expression. This method is called by the service using an Expression> LINQ expression. So, I've used Automapper to map the service's expression to the repository's expression.
The project builds successfully but I have an error at runtime.
This is the method that throws the error in the service:
public IQueryable<TDto> GetBy(Expression<Func<TDto, bool>> predicate)
=> this.Repository.GetBy(Mapper.Map<Expression<Func<TEntity, bool>>>(predicate))
.ProjectTo<TDto>(Mapper.ConfigurationProvider);
And this is the method called in the repository:
public IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate)
=> this.Context.Set<TEntity>().AsNoTracking().Where(predicate);
The mapping between entity and dto is the following:
CreateMap<TEntity, TDto>();
CreateMap<TDto, TEntity>();
At runtime I'm receiving this error:
AutoMapper.AutoMapperMappingException: 'Missing type map configuration or unsupported mapping.'
Also, i've tryed to map explicitly the expressions:
CreateMap<Expression<Func<TEntity, bool>>, Expression<Func<TDto, bool>> >();
CreateMap<Expression<Func<TDto, bool>>, Expression<Func<TEntity, bool>>>();
But i've received this error:
System.InvalidOperationException: 'Code supposed to be unreachable'
Does anyone have a possible solution?
I have never seen capability to automaticaly transform lambdas.
What you should do instead is to try use Project method.
For example:
var predicate = new Func<Dto, bool>(d => d.Id == 2);
var query = mapper.ProjectTo<Dto>(entities, null).Where(predicate);
Query will be equivalent of:
var query = entities
.Select(e => new Dto { Id = e.Id, [...] }) // mapping created using map registered in AutoMapper
.Where(d => d.Id == 2)
Another thing you can do is to map expression by yourself. As a starpoint you can use query produced by Project method:
var query = mapper.ProjectTo<Dto>(entities, null);
var lambda = (LambdaExpression)((UnaryExpression)((MethodCallExpression) query.Expression).Arguments[1]).Operand;
var body = (MemberInitExpression)lambda.Body;
var bindings = body.Bindings;
As a result of the code above you will have array of bindings like dto.Id = entity.Id.
Having that it should be pretty easy to write custom mapper:
public static class MapperExtensions
{
public static Expression<Func<TEntity, bool>> ConvertPredicate<TDto, TEntity>(this Mapper mapper, Expression<Func<TDto, bool>> predicate)
{
return (Expression<Func<TEntity, bool>>)new PredicateVisitor<TDto, TEntity>(mapper).Visit(predicate);
}
public class PredicateVisitor<TDto, TEntity> : ExpressionVisitor
{
private readonly ParameterExpression _entityParameter;
private readonly MemberAssignment[] _bindings;
public PredicateVisitor(Mapper mapper)
{
IQueryable<TDto> mockQuery = mapper.ProjectTo<TDto>(new TEntity[0].AsQueryable(), null);
LambdaExpression lambdaExpression = (LambdaExpression)((UnaryExpression)((MethodCallExpression) mockQuery.Expression).Arguments[1]).Operand;
this._bindings = ((MemberInitExpression)lambdaExpression.Body).Bindings.Cast<MemberAssignment>().ToArray();
this._entityParameter = Expression.Parameter(typeof(TEntity));
}
// This is required to modify type parameters
protected override Expression VisitLambda<T>(Expression<T> node)
{
return Expression.Lambda(
base.Visit(node.Body),
node.Parameters.Select(p => (ParameterExpression)base.Visit(p)).ToArray()
);
}
// Do member mapping
protected override Expression VisitMember(MemberExpression node)
{
MemberInfo member = node.Member;
MemberAssignment binding = this._bindings.FirstOrDefault(b => b.Member == member);
if (binding != null)
{
return base.Visit(binding.Expression);
}
return base.VisitMember(node);
}
// Replace parameters reference
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(TDto))
{
return this._entityParameter;
}
if (node.Type == typeof(TEntity))
{
return this._entityParameter;
}
return base.VisitParameter(node);
}
}
}

Entity Framework LINQ Expression on object within object

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.

Create dynamic Expression<Func<T, bool>>

I don’t know if this is possible or not but I’m trying to refactor my code logic by doing the following;
I have a method called: ApproveProcess<T1, T2>(T1 classObject, T2 classSecondObject) where T : class
T is the generic object that I’m passing to the ApproveProcess method.
I have then the following method:
public IQueryable<T> GetById(Expression<Func<T, bool>> condition, Func<IQueryable<T>)
{
IQueryable<T> query = _entities.Where(condition);
return query;
}
I am trying to do the following:
Expression<Func<T1, bool>> expr2 = z => z.GetType().GetProperty("StringNumber").ToString() == "IB56";
BaseRepository<T1> iBase = new BaseRepository<T>(_databaseContext);
var tester1 = iBase. GetById(expr2, null).ToList();
I am trying to dynamically create the expression function based on the generic T object to then returns results.
I am not getting anyway. If I change
`Expression<Func<T1, bool>> expr2'
to
Expression<Func<actualObject, bool>> expr2
I then get the following error
Error CS1503 Argument 1: cannot convert from 'System.Linq.Expressions.Expression>' to 'System.Linq.Expressions.Expression>'
Is anyone able to tell me if what I am trying to do is actually possible?
Any pointers to point me in the right direction would be grateful / Help?
Code Sample below;
_uowAdmin.AdminRepository.ApproveProcess<MeetingOne, MeetingRoomOne, MeetingRoomTwo>(new MeetingRoomOne(), new MeetingRoomTwo());
_uowAdmin.AdminRepository.ApproveProcess<DiningOne, DiningRoomOne, DiningRoomTwo>(new DiningRoomOne(), new DiningRoomTwo());
public void ApproveProcess<T, T1, T2>(T1 classObject, T2 classSecondObject) where T : class
{
BaseRepository<T> iBase = new BaseRepository<T>(_databaseContext);
Expression<Func<T, bool>> expr2 = z => z.GetType().GetProperty("StringNumber").ToString() == "IB56";
var tester1 = iBase.GetById(expr2, null).ToList();
}
public class BaseRepository<T> where T : class
{
public IQueryable<T> GetById(Expression<Func<T, bool>> condition, Func<IQueryable<T>)
{
IQueryable<T> query = _entities.Where(condition);
return query;
}
}
Try this:
var parameter = Expression.Parameter(typeof(T), "z");
var expr2 = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Property(parameter, "StringNumber"),
Expression.Constant("IB56")),
parameter);

Add And statement to Expression<Func<T, bool>>

I have this function:
public List<T> Find(Expression<Func<T, bool>> query)
{
}
Find(x => x.Id == 4);
Inside the method Find I want to chain And Condition.
something like:
query.And(x => x.Secured == false);//Secured is a memeber inside T like Id.
Your problem is that you want to access a member of T within the generic method. T could be anything at this point so the compiler will not let you access Secured since T may not have a Secured member.
You could cast T to dynamic, but this just changes a compile time error to a runtime error (plus it's horrible).
The best way would be to ensure T implements some known interface that has a Secured member.
public List<T> Find(Expression<Func<T, bool>> query) where T : ISecured
The expression must be "opened" and rebuilt, like this:
public List<T> Find<T>(Expression<Func<T, bool>> query)
{
ParameterExpression parameter = query.Parameters[0];
Expression body = query.Body;
MemberExpression property = Expression.Property(parameter, "Secured");
body = Expression.AndAlso(body, Expression.Not(property));
Expression<Func<T, bool>> query2 = Expression.Lambda<Func<T, bool>>(body, parameter);
// Now you can use query2
return null;
}
Note that I'm considering this x.Secured == false to be equivalent to !x.Secured. Clearly Secured could be a strange class that overloads the == operator, but I'll ignore that case.
As suggested by #Ralf, you could even simply do two .Where. like:
public List<T> Find<T>(Expression<Func<T, bool>> query)
{
ParameterExpression parameter = query.Parameters[0];
MemberExpression property = Expression.Property(parameter, "Secured");
Expression<Func<T, bool>> query2 = Expression.Lambda<Func<T, bool>>(Expression.Not(property), parameter);
return context.Set<T>
.Where(query)
.Where(query2)
.ToList();
}
(I'm using as an example context.Set<T>, that is very similar to what you would do if you are using Entity Framework, but in general nearly all the IQuerable<>/IEnumerable<> treat two .Where() like a single .Where() with an && condition)
Something like
Find(x => x.Id == 4 && x.Secured == false);

How do I read an Expression's contents?

I have a class that works as a repository of some sort, and grants access to a database. I'm trying to customize it to allow queries with expressions.
So, I want to be able to do this:
IList<MyClass> myList = myRepository.GetBy(x => x.Name == "SomeName");
//and...
IList<MyClass> myList2 = myRepository.GetBy(x => x.Name == "SomeName" && x.ID = 5);
This is what I need to have on the repository function:
public IList<T> GetBy(Expression<Func<T, bool>> expression)
{
//Set up the query, etc
//I'm at the WHERE clause, and I need to get the property(ies) name(s) of the expression and their values to properly set the WHERE
}
How can I do this?
What you want to do is this:
IList <MyClass> myList2 = myRepository.GetBy (x => x.Name == "SomeName" && x.ID = 5);
It is true that you can represent x => x.Name == "SomeName" && x.ID = 5 with Expression <Func <T, bool >>
but also what you can do with the delegate Func <T, bool> only.
Regardless of which were to take the data will always be from an IEnumerable <T> so you always will have the Where method (whenever you use the namespace System.Linq), which accepts as a parameter a delegate Func <T, bool> . If the object IEnumerable <T> is a DbSet <T>, this will take care of transforming the delegate Func <T, bool> in a sql query. Remember that a Linq query, which is what is being used, is only executed when the query data is used or agrees with methods ToList () or ToArray () for example.
example:
IEnumerable <MyClass> list = ... from wherever you get the data even from DbSet of EntityFramework
var query = list.Where (x => x.Name == "SomeName" && x.ID = 5);
query is a shost a query, it contains no data until this is done
foreach (var x in list) is being consumed, so the query is executed
{
   var c = x.Name;
}
or this
`var temp = query.ToList ();`
This force to stored in a List <MyClass>
With all this I want to say that if you use the DbSet of EntityFramework, what happens is that the delegate Func <T, bool> is transformed into a sql query, so that the data manager is responsible for filtering data (as it should be).
 From this alone you would have to simply have your method
public IList <T> GetBy (Func <T, bool> expression)
{
    origen.Where (expression).ToList();
}
if I understand your question correctly, you shoul inherit you repository interfaces from base generic repository interface.
public interface IRepositoryBase<TEntity>
{
IList<TEntity> GetBy(Expression<Func<TEntity, bool>> expression)
}
and repository realisation from base repository implementation
public abstract class RepositoryBase<TEntity>: IRepositoryBase<TEntity>
{
public MyEntities EntitiesContext { get; set; }
public IList<TEntity> GetBy(Expression<Func<TEntity, bool>> expression)
{
return EntitiesContext.Set<TEntity>().Where(filter).ToList()
}
}

Categories

Resources