How to make IList compatible to IEnumerable during lambda expression? - c#

I'm trying to convert this:
ISession.Query<Question>()
.Where(x => x.QuestionId == q.QuestionId)
.FetchMany(x => x.Answers)
.ToFuture();
To reflection type:
IQueryable<Question> query = ISession.Query<Question>().Where(string.Format("{0} = #0", "QuestionId"), q.QuestionId);
Type emType = typeof(NHibernate.Linq.EagerFetchingExtensionMethods);
MethodInfo mi = emType.GetMethod("FetchMany");
ParameterExpression paramEx = Expression.Parameter(typeof(Question), "x");
MemberExpression me = Expression.Property(paramEx, "Answers");
LambdaExpression lambdaEx = Expression.Lambda (me, paramEx);
// runtime error here
mi.MakeGenericMethod(typeof(Question), typeof(Answer)).Invoke(emType, new object[] { query, lambdaEx });
The runtime error:
System.ArgumentException: Object of type
'System.Linq.Expressions.Expression`1
[System.Func`2[TestXXX.TheModels.Question,
System.Collections.Generic.IList`1[TestXXX.TheModels.Answer]]]'
cannot be converted to type
'System.Linq.Expressions.Expression`1
[System.Func`2[TestXXX.TheModels.Question,
System.Collections.Generic.IEnumerable`1[TestXXX.TheModels.Answer]]]'.
POCO sample:
The Answers in Question is an IList, please don't advise to change IList to IEnumerable ;-)
public class Question
{
public virtual int QuestionId { get; set; }
public virtual string QuestionText { get; set; }
public virtual IList<Answer> Answers { get; set; }
}
Here's the method signature of FetchMany:
namespace NHibernate.Linq
{
public static class EagerFetchingExtensionMethods
{
public static INhFetchRequest<TOriginating, TRelated> Fetch<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector);
public static INhFetchRequest<TOriginating, TRelated> FetchMany<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector);
public static INhFetchRequest<TQueried, TRelated> ThenFetch<TQueried, TFetch, TRelated>(this INhFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, TRelated>> relatedObjectSelector);
public static INhFetchRequest<TQueried, TRelated> ThenFetchMany<TQueried, TFetch, TRelated>(this INhFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, IEnumerable<TRelated>>> relatedObjectSelector);
}
}
What should be done so it's possible to pass an IList to NHibernate's FetchMany's IEnumerable during reflection?
Note: can pass IList to IEnumerable if we are not using reflection

Change this
MemberExpression me = Expression.Property(paramEx, "Answers");
to this:
Expression me = Expression.Convert(Expression.Property(paramEx, "Answers"), typeof(IEnumerable<Answer>));
The reason for the error you are receiving is that the delegate types of your lambda do not agree. We need to make the types compatible by artificially treating an IList<T> as an IEnumerable<T>.
This is kind of a hack as any proponent of dynamic languages would say ;-) Anyway, it reliably works.

Related

Re-implementation of OrderBy, ThenBy and Null TypeMapping in Sql Tree error

I am trying to implement OrderBy and ThenBy in a different way to hide lambda expression from OrderBy and ThenBy extension methods. These extension methods accept classes which implement IOrderSpecification:
public class PersonOrderByAgeSpecification : OrderSpecification<Person>
{
public PersonOrderByAgeSpecification(Sort direction= Sort.Ascending) : base(direction)
{
}
public override Expression<Func<Person, IComparable>> AsExpression()
{
return personOrder => personOrder.Age;
}
}
And the usage:
var orderSpecification = new PersonOrderByAgeSpecification(Sort.Ascending);
var sortedPeople= _dbContext.People.OrderBy(orderSpecification);
It works fine when the property type in AsExpression() is just string. For example:
public override Expression<Func<Person, IComparable>> AsExpression()
{
return personOrder => personOrder.FirstName;
}
Otherwise I would get this error: (Does not work with integer or bool)
InvalidOperationException: Null TypeMapping in Sql Tree
Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalSqlTranslatingExpressionVisitor+SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression
node)
The source code is available here
I appreciate any help.
First off, you are using preview (beta) software, which is expected to have issues.
But the main problem is that LINQ ordering methods have second generic type argument TKey, which you are hiding behind IComparable, which for value types causes a hidden cast inside the expression.
Apart from unnecessary boxing, this is not a problem for LINQ to Objects provider because it simply compiles and executes a delegate from the lambda expression. However other IQueryable providers usually need to translate the expression to something else (usually SQL). Most of them identify such casts (Expression.Convert) and remove them during the processing. Apparently EF 3.0 preview you are using doesn't, hence the exception.
You can avoid such issues by eliminating the hidden casts yourself. It's possible to do that with expression manipulation, but the easiest is to introduce the second generic type argument to your base abstract class:
public abstract class OrderSpecification<T, TKey> : IOrderSpecification<T>
and change the abstract method signature to
public abstract Expression<Func<T, TKey>> AsExpression();
The implementation, interface and everything else except the concrete classes will remain as is.
Now all you need is to specify the actual key type in the inherited class and change the AsExpression override signature. For instance:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class PersonAgeOrderSpecification : OrderSpecification<Person, int>
{
public PersonAgeOrderSpecification(Sort direction) : base(direction) { }
public override Expression<Func<Person, int>> AsExpression()
{
return person => person.Age;
}
}
and everything will be fine.

C# Type Mirroring

Is it possible in C# to have something I could call dynamic type mirroring, for lack of a better term?
Say, an application talks to a database that has multiple tables, each of which has an entity in the code of the usual sort:
public class SomeEntity
{
int ID { get; set; }
string Name { get; set; }
};
etc.
Now, is it possible to have a class that dynamically mirrors the types of these entities:
public class FilterType<T, U>
{
T Field1;
bool Apply<T>(T operand, T comparand);
};
such that T is dynamically int, for instance?
If I recall right, generics are compile-time determined, so this wouldn't be possible. Is there anything that could approximate this behaviour?
I need this to be able to filter fields in a table, and ideally I want this to be as generic as possible with minimal coupling. To add more substance, here's some code from my filter types:
public interface IFilter
{
string Representation { get; }
}
public interface IFilterBinary : IFilter
{
bool Apply<T>(T source, T operand1, T operand2) where T : IComparable;
}
public interface IFilterUnary : IFilter
{
bool Apply<T>(T source, T operand) where T : IComparable;
}
public class IsGreaterOrEqual : IFilterUnary
{
public string Representation { get; } = ">=";
public bool Apply<T>(T source, T operand) where T : IComparable
{
return source.CompareTo(operand) >= 0;
}
}
The problem with this is that when I try to use the filters, I hit a snag:
var property = typeof (User).GetProperties().Single(x => x.Name == rule.FieldName);
var fieldValue = property.GetValue(user);
var fieldType = property.PropertyType;
var value = Convert.ChangeType(fieldValue, fieldType); // Here the return type is `object`, so this line is useless.
Applying the filter filter.Apply(value, operand) fails because value is an object.
Thanks.
I think better for you using DynamicLinq lib.
As for your current approach, if you use reflection for getting value, just use it for calling function, like this:
var property = typeof (User).GetProperty(rule.FieldName);
var fieldValue = property.GetValue(user);
var fieldType = property.PropertyType;
var result = filter.GetType().GetMethod("Apply").MakeGenericMethod(fieldType).Invoke(filter, fieldValue, operand);
but anyway in this case result was boxed to object.

Query over interface properties using EntityFramework and LinqKit

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);
}
}

Generic constraints with C# Expression<TDelegate> - Cannot implicitly convert Type

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);
}
}

Building LINQ Expressions Dynamically w/ Unknown Types

I am wondering if it is possible to use this expression builder class to generate lambda expressions dynamically where the type to be filtered is not known at compile time.
I have a method that constructs the expression,
public static Expression<Func<T, bool>> GetExpression<T>(IList<QueryFilter> filters)
And a QueryFilter object,
public class QueryFilter
{
public string PropertyName { get; set; }
public ExpressionType OpType { get; set; }
public object Value { get; set; }
}
Where you can generate a new expression that filters object T using the QueryFilters that are passed in. I want to develop a method where the type isn't known, ie.
public static Expression<Func<T,bool>> GetExpression(IList<QueryFilter> filters, Type type)
So I can pass the type as a parameter, from calls to System.Reflection, instead of having to specify it in code. For example something along these lines,
public static Expression NewExpression(IList<QueryFilter> filters, Type T)
{
return GetExpression<Type>(filters);
}
If its possible to use this syntax where Type replaces the generic 'T'? Since I do not think I can specify a runtime dynamic Type within the < > brackets, is there another way, perhaps using
Func<object,bool>
instead?
Try working with DynamicExpression.ParseLambda
You can use either Predicate Builder or the Dynamic Linq Library (.NET 3.5).

Categories