I have a problem regarding generic expressions.
I have an Expression<Func<T, bool>> and I want to convert the Expression<Func<T, bool>> to Expression<Func<Y, bool>>. The object of class T has the same properties as the class Y.
Does anybody know how to solve this?
The "preferred" way to do this is use a Interface that contains the property you care about.
interface IMyProp
{
string SomeProp {get;}
}
class T : IMyProp
{
public string SomeProp
{
get
{
//Some complicated logic
}
}
}
class Y : IMyProp
{
public string SomeProp {get; set;}
}
The just code your expression to Expression<Func<IMyProp, bool>>
However it is understandable that you can not always do this, for situations like this you can use a library like AutoMapper
class T
{
public string SomeProp
{
get
{
//Some complicated logic
}
}
}
class Y
{
public string SomeProp {get; set;}
}
//Some initiation code somewhere else in your project
public static void InitializeMappings()
{
Mapper.CreateMap<T, Y>();
}
public static IQueryable<Y> FilterOnTAndMapToY(IQueryable<T> source, Expression<Func<T,bool>> filter)
{
return source.Where(filter).Project().To<Y>();
}
Now this does not exactly turn your Expression<Func<T, bool>> in to a to Expression<Func<Y, bool>> but it does let you use your T expression and use it to get a Y result after the filtering has been applied.
The way AutoMapper's Queryable Extensions work is the querys and casts to go from T to Y happen all server side when you are doing LinqToEntities. So you could even do
public static IQueryable<Y> MultiFilterCast(IQueryable<T> source, Expression<Func<T,bool>> tTypeFilter, Expression<Func<Y,bool>> yTypeFilter)
{
var filteredStage1 = source.Where(tTypeFilter);
var castToY = filteredStage1.Project().To<Y>();
var filteredStage2 = castToY.Where(yTypeFilter);
return filteredStage2;
}
both tTypeFilter and yTypeFilter will be applied server side before you get the result set.
Related
I'm trying to implement class that defines filter, to make it more explicit when it will be passed as argument to methods in my repository class (EF).
And I have a problem with definition of implicit operator from Expression to my class.
Is it possible to make implementation for syntax near fd4 variable?
public class FilterDefinition<TEntity>
where TEntity : class
{
public FilterDefinition() { }
public FilterDefinition(Expression<Func<TEntity, bool>> filter)
{
this.Filter = filter;
}
public virtual Expression<Func<TEntity, bool>> Filter { get; set; }
public static implicit operator FilterDefinition<TEntity>(Expression<Func<TEntity, bool>> filter) => new FilterDefinition<TEntity>(filter);
}
public class SomeEntity
{
public bool SomeBool { get; set; }
}
class Program
{
static void Main()
{
FilterDefinition<SomeEntity> fd1 = new FilterDefinition<SomeEntity>(x => x.SomeBool);
FilterDefinition<SomeEntity> fd2 = new FilterDefinition<SomeEntity> { Filter = x => x.SomeBool };
FilterDefinition<SomeEntity> fd3 = (Expression<Func<SomeEntity, bool>>)(x => x.SomeBool);
//FilterDefinition<SomeEntity> fd4 = x => x.SomeBool;
Console.ReadKey();
}
}
The purpose of FilterDefinition class was to pass as argument to generic repository of queries. And using inheritance define commonly used filters.
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : class
{
private readonly DbSet<TEntity> dbSet;
public Repository(DbContext context)
{
this.dbSet = context.Set<TEntity>();
}
public async Task<IEnumerable<TEntity>> GetAsync(
FilterDefinition<TEntity> filter = null,
OrderDefinition<TEntity> order = null,
PagingDefinition paging = null)
{
return await new QueryBuilder<TEntity>(this.dbSet)
.ApplyFilter(filter)
.ApplyOrder(order)
.ApplyPaging(paging)
.ToQuery()
.ToListAsync();
}
The short answer would be "not in this scenario", because syntactically, in fd4 you're not actually casting from an Expression[...] to your type. The compiler doesn't know that the lambda represents an Expression[...] until it knows what it is trying to do with the value; a lambda (x => x.SomeBool) can be interpreted as a wide range of both expression-tree types and delegate types (for anonymous methods), and the compiler here would not understand that you mean "treat the lambda as an Expression<Func<SomeEntity, bool>>, then use the implicit conversion operator to change the expression to a FilterDefinition". It simply can't (and doesn't) make that leap. You can get close, as with your fd3 example, but... a large part of me is wondering what FilterDefinition actually does here, because to an outside observer it doesn't really seem to add anything over the raw expression tree.
Let A be a class whith some property Hello. I would like to filter collections of A instances by this property in many places. Thus I'd make somewhere a static member of type Expression<Func<A, bool>> which denotes the filtering predicate and I use it in all places where I do a filtering. (This predicate would be transformed by an ORM to some concrete DB-specific expression.)
Next. There exists a class B with property of type A. I would like to filter collection of B instances by the same logic as was used in the first case (by property Hello of class A).
Question. What is the most correct way to implement this and reduce code duplication?
My suggestion. Add three things: 1) interface IWithA with property of type A, 2) class WithA<T> implementing this interface IWithA and providing property of type T, 3) some static property of type Expression<Func<IWithA, bool>> implementing the filtering logic. Demo code is following.
public static void Main() {
var listOfAs = new List<A>().AsQueryable();
var query0 = listOfAs
.Select(a => new WithA<A> {
A = a,
Smth = a,
})
.Where(Filter);
var listOfBs = new List<B>().AsQueryable();
var query1 = listOfBs
.Select(b => new WithA<B> {
A = b.A,
Smth = b,
})
.Where(Filter);
}
private class A {
public int Hello { get; set; }
}
private class B {
public A A { get; set; }
}
private interface IWithA {
A A { get; set; }
}
private class WithA<T> : IWithA {
public A A { get; set; }
public T Smth { get; set; }
}
private static readonly Expression<Func<IWithA, bool>> Filter = a => a.A.Hello > 0;
The problem with this approach: 1) one must always make Select(x => new WithA<X> { ... }), 2) the ORM may not support this.
About the answer. I am satisfied with the accepted answer (by Ivan Stoev). I think it is the best possible approach. Also it is helpful to look at the suggestion from Mihail Stancescu (see it in comments to the question). Still I do not understand the answer from user853710; may be it is useful also.
I would create and use a helper function that converts the original Expression<A, bool> to Expression<B, bool> using the System.Linq.Expressions like this
public static class ExpressionUtils
{
public static Expression<Func<TTarget, bool>> ConvertTo<TSource, TTarget>(this Expression<Func<TSource, bool>> source, Expression<Func<TTarget, TSource>> sourceSelector)
{
var body = new ParameterExpressionReplacer { source = source.Parameters[0], target = sourceSelector.Body }.Visit(source.Body);
var lambda = Expression.Lambda<Func<TTarget, bool>>(body, sourceSelector.Parameters);
return lambda;
}
class ParameterExpressionReplacer : ExpressionVisitor
{
public ParameterExpression source;
public Expression target;
protected override Expression VisitParameter(ParameterExpression node)
{
return node == source ? target : base.VisitParameter(node);
}
}
}
Sample usage
Expression<Func<A, bool>> filterA = item => item.Hello == 2; // The original logic
var filterB = filterA.ConvertTo((B b) => b.A);
This approach doesn't require any changes to your entity model. Of course you can cache the filters in a static properties of the respective classes if you wish, but the principle is still write the logic in one place and then just use convert in other places.
I would suggest you not to reinvent the wheel. Take a look at the Library LinqKit
The Predicatebuilder is what you need and it gives you much more. Albahari (The developer) has amazing products and libraries for sharing and give you much fun using threm
I'm using EntityFramework and LinqKit to build expressions trees which get translated into SQL. Also we use the specification pattern to organize our queries.
There is a need in almost all of our domain objects to execute a query by description, but in some of those classes the property is called "Name", in others "Description", etc.
So initially was defined a interface as follow:
public interface IDescritible
{
string Description { get; }
}
The problem appeared when I tried to use it implemented explicitly in a class and made a generic query upon that:
public class Foo : IDescritible
{
public string Name { get; set; }
string IDescritible.Description
{
get { return this.Name; }
}
}
public class DescriptionMatch<T> : AbstractSpecification<T>
where T : IDescritible
{
public string Query { get; set; }
public DescriptionMatch(string query)
{
this.Query = query;
}
public override Expression<Func<T, bool>> IsSatisfiedBy()
{
return x => x.Description.Contains(Query);
}
}
When run, the EntityFramework is unable to translate the property get (a method call) into a SQL expression.
Then I tried to define a Expression in the class as follows:
public interface IDescritible<T> where T: IDescritible<T>
{
Expression<Func<T, string>> DescriptionExpression { get; }
}
public class Foo : IDescritible<Foo>
{
public string Name { get; set; }
public Expression<Func<Foo, string>> DescriptionExpression
{
get { return x => x.Name; }
}
}
public class DescriptionMatch<T> : AbstractSpecification<T> where T : IDescritible<T>
{
public string Query { get; set; }
public DescriptionMatch(string query)
{
this.Query = query;
}
public override Expression<Func<T, bool>> IsSatisfiedBy()
{
Expression<Func<T, bool>> combinedExpression = x => x.DescriptionExpression.Invoke(x).Contains(this.Query);
return combinedExpression.Expand();
}
}
But when it executes the .Expand() a exception is thrown: Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Linq.Expressions.LambdaExpression'.
Then I found out that LinqKit only support expanding local defined expressions (as stated on this question) and that there are some unoficial code write to solve those issues (answers on this question).
But when I modified the LinqKit library to try either one of the proposed solutions in second question it started to throw: variable 'x' of type 'Foo' referenced from scope '', but it is not defined.
Maybe that was caused by the fact that I don't have a instance of Foo yet? Only got the generic type parameter, and that's why I can't define my expression on a local variable. Maybe there is a way to define as a static expression somehow "attached" into class? But then I would not be able to use it in a generic query, there will be no interface...
There is a way to modify LinqKit so I can build expressions defined on a explicit implementation of a interface? Or there is another way to make a generic query upon properties explicitly implemented? Or any other solution or things to look into?
There is no need to use neither LinqKit or specification pattern for that, but EntityFramework is mandatory, what is important is to have a interface/any other way that support "pointing out" which property is the description property and make a generic Expression upon that.
Thank you in advance!
The easiest way to do it is to make the following change
public class DescriptionMatch<T> : AbstractSpecification<T> where T : IDescritible<T>, new()
Then you can get an instance by simply newing up a T (which EF), using the expression and otherwise discarding the object
public interface IDescritible<T> where T : IDescritible<T>
{
Expression<Func<T, string>> DescriptionExpression { get; }
}
public class Foo : IDescritible<Foo>
{
public string Name { get; set; }
public Expression<Func<Foo, string>> DescriptionExpression
{
get { return x => x.Name; }
}
}
public abstract class AbstractSpecification<T>
{
public abstract Expression<Func<T, bool>> IsSatisfiedBy();
}
public class DescriptionMatch<T> : AbstractSpecification<T>
where T : IDescritible<T>, new()
{
public string Query { get; set; }
public DescriptionMatch(string query)
{
this.Query = query;
}
public override Expression<Func<T, bool>> IsSatisfiedBy()
{
Expression<Func<T, string>> lambda = new T().DescriptionExpression;
return Expression.Lambda<Func<T, bool>>(
Expression.Call(
lambda.Body,
"Contains",
Type.EmptyTypes,
Expression.Constant(
this.Query,
typeof(string)
)
),
lambda.Parameters
);
}
}
public class ExpressionReplacer : ExpressionVisitor
{
private readonly Expression _toBeReplaced;
private readonly Expression _replacement;
public ExpressionReplacer(Expression toBeReplaced, Expression replacement)
{
if (toBeReplaced.Type != replacement.Type)
{
throw new ArgumentException();
}
this._toBeReplaced = toBeReplaced;
this._replacement = replacement;
}
public override Expression Visit(Expression node)
{
return Object.ReferenceEquals(node, this._toBeReplaced) ? this._replacement : base.Visit(node);
}
}
How can I cast from
Expression<Func<T, bool>> predicate
to
Expression<Func<SomeType, bool>> predicate
?
Couldn't find a way so far. Or at least create a new Expression<Func<SomeType, bool>> by using the first one's string representation of the predicate.
If it helps, T is limited to types implementing ISomeInterface, and SomeType implements it.
LE: further clarification
The interface is something like:
public interface ICacheable
{
List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable;
}
then you have
public partial class Video : ICacheable
{
public List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
{
// implementation here that returns the actual List<Video>
// but when I try to query the dbcontext I can't pass a predicate with type T, I have to cast it somehow
List<Video> videos = db.Videos.Where(predicate).ToList(); // not working
}
}
then you have:
public class RedisCache
{
public List<T> GetList<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
{
List<T> objList = // get objects from cache store here
if(objList == null)
{
List<T> objList = GetObjects<T>(predicate);
// cache the result next
}
return objList;
}
}
I use the above from any class like so:
// If the list is not found, the cache store automatically retrieves
// and caches the data based on the methods enforced by the interface
// The overall structure and logic has more to it.
List<Video> videos = redisCache.GetList<Video>(v => v.Title.Contains("some text"));
List<Image> images = redisCache.GetList<Image>(v => v.Title.Contains("another text"));
And I would extend this to any type of object I need to be cachable, with methods that will allow the Cache store to automatically retrieve an entity or list of entities if they are not found in cache. I might be doing this completely wrong though.
I'm not up to scratch on my Entity Framework, but I know that the DatabaseContext within LINQ has a GetTable<T> which returns the table based on the generic. If "GetTable equivalent for ObjectContext" is anything to go by, it's also available in EF?
To make your statement truly generic, you could try this:
public MyBaseObject<T>
{
public List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
{
return db.CreateObjectSet<T>().Where(predicate).ToList();
}
}
public partial class Image : MyBaseObject<Image>, ICacheable
{
}
public partial class Video : MyBaseObject<Video>, ICacheable
{
}
Here is something (extremely) basic which, I hope, might help you in the process of caching using generics.
// ICacheable interface is used as a flag for cacheable classes
public interface ICacheable
{
}
// Videos and Images are ICacheable
public class Video : ICacheable
{
public String Title { get; set; }
}
public class Image : ICacheable
{
public String Title { get; set; }
}
// CacheStore will keep all objects loaded for a class,
// as well as the hashcodes of the predicates used to load these objects
public class CacheStore<T> where T : ICacheable
{
static List<T> loadedObjects = new List<T>();
static List<int> loadedPredicatesHashCodes = new List<int>();
public static List<T> GetObjects(Expression<Func<T, bool>> predicate)
{
if (loadedPredicatesHashCodes.Contains(predicate.GetHashCode<T>()))
// objects corresponding to this predicate are in the cache, filter all cached objects with predicate
return loadedObjects.Where(predicate.Compile()).ToList();
else
return null;
}
// Store objects in the cache, as well as the predicates used to load them
public static void StoreObjects(List<T> objects, Expression<Func<T, bool>> predicate)
{
var hashCode = predicate.GetHashCode<T>();
if (!loadedPredicatesHashCodes.Contains(hashCode))
{
loadedPredicatesHashCodes.Add(hashCode);
loadedObjects = loadedObjects.Union(objects).ToList();
}
}
}
// DbLoader for objets of a given class
public class DbStore<T> where T : ICacheable
{
public static List<T> GetDbObjects(Expression<Func<T, bool>> predicate)
{
return new List<T>(); // in real life, load objects from Db, with predicate
}
}
// your redis cache
public class RedisCache
{
public static List<T> GetList<T>(Expression<Func<T, bool>> predicate) where T:ICacheable
{
// try to load from cache
var objList = CacheStore<T>.GetObjects(predicate);
if(objList == null)
{
// cache does not contains objects, load from db
objList = DbStore<T>.GetDbObjects(predicate);
// store in cache
CacheStore<T>.StoreObjects(objList,predicate);
}
return objList;
}
}
// example of using cache
public class useRedisCache
{
List<Video> videos = RedisCache.GetList<Video>(v => v.Title.Contains("some text"));
List<Image> images = RedisCache.GetList<Image>(i => i.Title.Contains("another text"));
}
// utility for serializing a predicate and get a hashcode (might be useless, depending on .Equals result on two equivalent predicates)
public static class PredicateSerializer
{
public static int GetHashCode<T>(this Expression<Func<T, bool>> predicate) where T : ICacheable
{
var serializer = new XmlSerializer(typeof(Expression<Func<T, bool>>));
var strw = new StringWriter();
var sw = XmlWriter.Create(strw);
serializer.Serialize(sw, predicate);
sw.Close();
return strw.ToString().GetHashCode();
}
}
I've started using C# Expression constructs, and I've got a question about how generics are applied in the following situation:
Consider I have a type MyObject which is a base class for many different types. Inside this class I have the following code:
// This is a String Indexer Expression, used to define the string indexer when the object is in a collection of MyObjects
public Expression<Func<MyObject, string, bool>> StringIndexExpression { get; private set;}
// I use this method in Set StringIndexExpression and T is a subtype of MyObject
protected void DefineStringIndexer<T>(Expression<T, string, bool>> expresson) where T : MyObject
{
StringIndexExpression = expression;
}
This is how I use DefineStringIndexer:
public class MyBusinessObject : MyObject
{
public string Name { get; set; }
public MyBusinessObject()
{
Name = "Test";
DefineStringIndexer<MyBusinessObject>((item, value) => item.Name == value);
}
}
However in the assignment inside DefineStringIndexer I get the compile error:
Cannot implicitly convert type
System.Linq.Expression.Expression< MyObject, string, bool > to
System.Linq.Expression.Expression < MyBusinessObject, string, bool >>
Can I use Generics with C# Expressions in this situation? I want to use T in DefineStringIndexer so I can avoid casting MyObject inside the lambda.
The assignment will not work, because the Func<MyBusinessObject,string,bool> type is not assignment-compatible with Func<MyObject,string,bool>. However, the parameters of the two functors are compatible, so you can add a wrapper to make it work:
protected void DefineStringIndexer<T>(Func<T,string,bool> expresson) where T : MyObject {
StringIndexExpression = (t,s) => expression(t, s);
}
Would this work better for you?
Edit: Added <T> to constraint - think you will need that :)
class MyObject<T>
{
// This is a String Indexer Expression, used to define the string indexer when the object is in a collection of MyObjects
public Expression<Func<T, string, bool>> StringIndexExpression { get; private set;}
// I use this method in Set StringIndexExpression and T is a subtype of MyObject
protected void DefineStringIndexer<T>(Expression<T, string, bool>> expresson)
where T : MyObject<T> // Think you need this constraint to also have the generic param
{
StringIndexExpression = expression;
}
}
then:
public class MyBusinessObject : MyObject<MyBusinessObject>
{
public string Name { get; set; }
public MyBusinessObject()
{
Name = "Test";
DefineStringIndexer<MyBusinessObject>((item, value) => item.Name == value);
}
}