How to expand calling expressions other than predicates? - c#

I just discovered LINQKit and am quite happy that it seems to provide a solution for the common problem of wanting to factor out parts of complex linq queries.
All examples, however, show how to factor out predicates for where-clauses.
Although that's a very typical use-case, I also want to factor out other kinds of expressions, typically for selects. Let's say I have the following sub-expression:
Expression<Func<SomeFunkyEntity, String>> GetStatusFromSomeFunkyEntity()
{
return i =>
i.IsExercise ? "Excercise" :
i.IsExpired ? "Expired" :
(i.IsLocked ) ? "Locked" :
i.IsAdmitted ? "Admissible" : "Unusable";
}
Does LINQKit provide a way to expand a call to this? I tried:
var query =
from i in this.DbContext.MyFunkyEntities.AsExpandable()
select new SomeFunkyEntityWithStatus()
{
FunkyEntity = i,
Status = GetStatusFromSomeFunkyEntity().Invoke(i)
};
This complies, but fails at runtime in LINQKit's expander:
Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'.
The stack trace starts with:
at LinqKit.ExpressionExpander.VisitMethodCall(MethodCallExpression m)
at LinqKit.ExpressionVisitor.Visit(Expression exp)
at LinqKit.ExpressionVisitor.VisitMemberAssignment(MemberAssignment assignment)
...
Is this not supported, or do I do something wrong?

Have you tried to assign the expression to a local variable before calling invoke?
var statusFromSomeFunkyEntity = GetStatusFromSomeFunkyEntity();
var query =
from i in this.DbContext.MyFunkyEntities.AsExpandable()
select new SomeFunkyEntityWithStatus()
{
FunkyEntity = i,
Status = statusFromSomeFunkyEntity.Invoke(i)
};
Check out this answer.

Related

Get Right value from LanguageExt c#

I have method that returns:
Either<Error, (int seconds, int count)> result = GetResult();
I need to return right value: (int NextDelayMs, int NextRetryCount)
But I can't figure out how to do it.
I tried:
var toReturn = result.Map(x => x.Right);
but I get IEnumerable this way. What am I doing wrong?
You have to handle the left case as an Either value can be left type L or right type R.
If you want to throw an exception when result is an Error you can use this:
var toReturn = result.IfLeft(err => throw err.ToException());
But you should avoid this. It's better to stay within Either using Map/Select and pass any errors to the calling method:
var errorOrFunctionResult = result.Map(x => someFunction(x));
If you want to supply a fallback value in case of an error:
var toReturn = result.IfLeft((100, 0))
Basically Either is similar to Option regarding usage and you can find a good introduction here: https://github.com/louthy/language-ext/#option

Creating an IQueryable to Equal int32?

I am trying to create an query extension which would compare a nullable int sql column value with a value. But i am struggling already over 8 hours to find any working solution.
I have already found a lot of help on this side. But all the remarks did not helped me.
I have altered the code so many times, but nothing seems to work. I want to create something similar as WHERE ManagerID IN (10,20,30)
The main code
IQueryable<Users> query = _context.CreateObjectSet<Users>();
query = query.IsMember(a => a.ManagerID, new Int32?[] { 10,20,30 });
return query.ToList();
Currently while executing the query.ToList(); it returns me a
Unable to create a constant value of type 'System.Object'. Only primitive types or enumeration types are supported in this context.
public static IQueryable<T> IsMember<T>(this IQueryable<T> source, Expression<Func<T, Int32?>> stringProperty, params Int32?[] searchTerms)
{
if (searchTerms == null || !searchTerms.Any())
{
return source;
}
Expression orExpression = null;
foreach (var searchTerm in searchTerms)
{
var searchTermExpression = Expression.Constant(searchTerm, typeof(object)); // <<--- This cast would make it no longer a primitive type
var containsExpression = Expression.Call(stringProperty.Body, typeof(Int32?).GetMethod("Equals"), searchTermExpression);
orExpression = BuildOrExpression(orExpression, containsExpression);
}
var completeExpression = Expression.Lambda<Func<T, bool>>(orExpression, stringProperty.Parameters);
return source.Where(completeExpression);
}
private static Expression BuildOrExpression(Expression existingExpression, Expression expressionToAdd)
{
return existingExpression == null ? expressionToAdd : Expression.OrElse(existingExpression, expressionToAdd);
}
The line marked to give the constant another datatype, is indeed causing the issue, but if I dont make it of type object, the Expression will not work, as it could not match the Int32? datatype.
Can anybody help me?
thanks
=============================================
Additional info
It is indeed to had a a larger picture.
I just want to create something more dynamic which could be used on other projects also.
I would like to use some functions which will look appealing than all those multilines
query = query.Like(a => a.UserName, filter.UserName, true);
query = query.Equals(a => a.UserTown, filter.UserTown, true);
query = query.IsMember(a => a.Division, filter.Division); // is an array of possible divisions
it worked fine for Like and Equals which are string based. But want to have a similar product for (nullable) integers
I was inspired by the following post. Which created a search function (which i renamed for my project to Like)
link
I wanted to create others similar. the last boolean is to verify if nullable in the column is allowed or not.
The reason also to use an extension, is that i also have alot of filters in my filter page.
With this extension, i would easily check in the beginning of my Like and Equal function if a filter was given without checking if my filter has a value 20x.
public static IQueryable<T> Like<T>(this IQueryable<T> source, Expression<Func<T, string>> stringProperty, string searchTerm, bool isnullValueAllowed)
if (String.IsNullOrEmpty(searchTerm))
{
return query;
}
It's not clear why you want to create this extension as you could simply write something like:
query.Where(user => (new[]{10,20,30}).Contains(user.ManagerId)).ToList();
However, assuming the real use case is somewhat more complicated than the example you've given, could you not construct your expression as either a comparison against a constant Int32 or a comparison against null, depending on whether searchTerm.HasValue() was true?
You need to use the equality operator == rather than the Equals method here. It actually makes your expression code a tad simpler:
foreach (var searchTerm in searchTerms)
{
var comparison = Expression.Equals(stringProperty.Body,
Expression.Constant(searchTerm));
orExpression = BuildOrExpression(orExpression, comparison);
}
Of course, as is mentioned by others, you don't need to build up an expression representing an OR of each of these comparisons, you can simply use Conatains on the set in a lambda and the query provider will do all of this for you.

Building a common set of methods that can operate on any linq table

Problem: We make extensive use of a repository pattern to facilitate read/write operations on our datastore (MS SQL using LINQ) across multiple applications and subsections of functionality. We have series of methods that all do something similar to each other.
For example, we have the ProcessAndSortXXXXX class of methods.
private static IEnumerable<ClassErrorEntry> ProcessAndSortClassErrorLog(IQueryable<ClassErrorDb> queryable, string sortOrder)
{
var dynamic = queryable;
if (!String.IsNullOrEmpty(sortOrder.Trim()))
{
dynamic = dynamic.OrderBy(sortOrder);
}
return dynamic
.Select(l =>
new ClassErrorEntry(l.Id)
{
ClassId = l.ClassId,
Code = l.Code,
Message = l.Message,
Severity = l.Severity,
Target = l.Target
}
);
}
...and...
private static IEnumerable<ClassTimerLogEntry> ProcessAndSortClassTimerLog(IQueryable<ClassTimerDb> queryable, string sortOrder)
{
var dynamic = queryable;
if (!String.IsNullOrEmpty(sortOrder.Trim()))
{
dynamic = dynamic.OrderBy(sortOrder);
}
return dynamic
.Select(l =>
new ClassTimerLogEntry(l.Id)
{
ClassName = l.ClassName,
MethodName = l.MethodName,
StartTime = l.StartTime,
EndTime = l.EndTime,
ParentId = l.ParentId,
ExecutionOrder = l.ExecutionOrder
}
);
}
As you can tell by the code, they're all very similar until you look at the signature and then get to the the return statement where we're building out the instances of the ClassErrorEntry and ClassTimerLogEntry.
I want to build a utility method that I'll add into the base class that all of the repositories inherit from.
I want to be able to pass in arguments that can be used to instantiate the objects and pack them into the returning IEnumerable.
I found this post by ScottGu and that gets me most of what I need. It looks like this (from the sample in the documentation):
var query =
db.Customers.
Where("City = #0 and Orders.Count >= #1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
Here's where I get stuck, though. I need a pointer or suggestion how I can pass in the LINQ tables and DataContext in a generic fashion so I can build out the dynamic query.
If I were to mock up the signature in pseudocode I think it would look something like this:
protected internal IEnumerable ProcessAndSort(IQueryable source, string selectClause, string whereClause, string orderByClause);
I realize that the finished signature may look different as we figure this out.
Thank you!
Update!
I now have code that works to generate an anonymous type but fails when converting to the concrete type.
public static IEnumerable<TResult> ProcessAndSort<T, TResult>(IQueryable<T> queryable,
string selector, Expression<Func<T, bool>> predicate, string sortOrder)
{
var dynamic = queryable.Where(predicate).AsQueryable();
if (!String.IsNullOrEmpty(sortOrder.Trim()))
{
dynamic = dynamic.OrderBy(sortOrder);
}
var result= dynamic.Select(selector).Cast<TResult>();
return result;
}
Here is the code that calls this method:
[TestMethod]
public void TestAnonymousClass()
{
var loggingContext = new LoggingDbDataContext(DatabaseConnectionString);
var repo = new LoggingRepository(loggingContext);
var result = repo.TestGetClassErrorLog(4407, 10, 0,
"new ( ClassId as ClassId, " +
"Code as Code, " +
"Message as Message, " +
"Severity as Severity, " +
"Target as Target )", "Target");
TestContext.WriteLine(result.ToList().Count.ToString());
}
The last line TestContext.WriteLine(result.ToList().Count.ToString()); throws the exception System.InvalidOperationException: No coercion operator is defined between types 'DynamicClass1' and 'Utilities.Logging.ClassErrorEntry'.
This chunk of code, though fails:
[TestMethod]
public void TestNamedClass()
{
var loggingContext = new LoggingDbDataContext(DatabaseConnectionString);
var repo = new LoggingRepository(loggingContext);
var result = repo.TestGetClassErrorLog(4407, 10, 0,
"new ClassErrorEntry(Id) { ClassId = ClassId, " +
"Code = Code, " +
"Message = Message, " +
"Severity = Severity, " +
"Target = Target }", "Target");
TestContext.WriteLine(result.ToList().Count.ToString());
}
This fails on a parsing error. Test method eModal.Repositories.Test.RepositoryBaseTest.TestConcreteClass threw exception:
System.Linq.Dynamic.ParseException: '(' expected, found 'ClassErrorEntry' ('Identifier') at char 19 in 'new ClassErrorEntry(Id) { ChassisAuthId = ChassisAuthId, Code = Code, Message = Message, Severity = Severity, Target = Target }'
I'm not sure that the character position is suspectas the 19th character position is a ( and the type passed into the Validate method indicates a position of 4, or the first 'C'.
I would completely advise you against making weakly typed queries just for the sake of code reuse.
Code reuse is for increasing maintainability, but weak typing can kill it, if used in a wrong way.
By writing your queries in plain text, you're effectively making the classes very hard to refactor and change, and introduce a lot of obscure dependencies.
I suggest you take a look at LinqKit that allows to combine Expressions. For example, we wrote a Paging method that splits query by pages and use it across the project with different types:
var query = CompiledQuery.Compile(
BuildFolderExpr( folder, false )
.Select( msg => selector.Invoke( msg, userId ) ) // re-use selector expression
.OrderBy( mv => mv.DateCreated, SortDirection.Descending )
.Paging() // re-use paging expression
.Expand() // LinqKit method that "injects" referenced expressions
)
public static Expression<Func<T1, T2, PagingParam, IQueryable<TItem>>> Paging<T1, T2, TItem>(
this Expression<Func<T1, T2, IQueryable<TItem>>> expr )
{
return ( T1 v1, T2 v2, PagingParam p ) => expr.Invoke( v1, v2 ).Skip( p.From ).Take( p.Count );
}
In my example, BuildMessageExpr returns a relatively simple select expression (which already depends on folder and another parameter), and different methods reuse this expression by applying filtering, ordering, getting count, further selecting with selector expression being passed as a parameter, et cetera. Once the query is created, it gets cached for future usage when parameters are similar.
It is not a direct answer to your question.
As you have said you have quite a lot code that look similar but return different types. If you will go ahead and look for generic implementation of this approach, the result may have a few hacks, you may still pass some uncomfortable SQL or check the type of the object or do some reflection kung-fu. You may still select this pass and actually someone can have a sensible idea that wouldn't look like a dirty hack.
The other option is to use a proper ORM with generic repository pattern and dependency injection(google link). Your data access layer will look much simpler and easier to maintain.

Extending LINQ to Nhibernate provider, in combination with Dynamic LINQ problem

I'm using NHibernate 3.1.0 and I'm trying to extend the LINQ provider by using BaseHqlGeneratorForMethod and extending the DefaultLinqToHqlGeneratorsRegistry as explained in Fabio's post.
For example, to support ToString() I've created a ToStringGenerator as below.
internal class ToStringGenerator : BaseHqlGeneratorForMethod
{
public ToStringGenerator()
{
SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition<object>(x => x.ToString())
};
}
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
return treeBuilder.Cast(visitor.Visit(targetObject).AsExpression(), typeof(string));
}
}
and I have registered using
internal class CustomLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public CustomLinqToHqlGeneratorsRegistry()
{
this.Merge(new ToStringGenerator());
}
}
etc. So far this works for "static" queries, I can use it like this:
var results = mSession.Query<Project>();
string pId = "1";
results = results.Where(p => p.Id.ToString().Contains(pId));
This translates correctly to its SQL counterpart (using SQL Server 2008)
where cast(project0_.Id as NVARCHAR(255)) like (''%''+#p0+''%'')
The problem arises when I try to use it in combination with Microsoft Dynamic LINQ library (discussed in this Scott Guthrie's post) like this:
var results = mSession.Query<Project>();
string pId = "1";
results = results.Where("Id.ToString().Contains(#0)", pId);
This results in a NotSupportedException with a message of "System.String ToString()" (which was the exact same messages I was getting with the static queries before implementing the classes mentioned above). This exception is being thrown with a source of "NHibernate" and with the StackTrace at "at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression)".
So what am I missing here? What have I done wrong, or what needs to be done to support this scenario?
I had the same problem and fixed it.
At first I want to thank murki for providing the information which got me on my way! The answer lies partly in Fabio's post. To solve this issue you have to use the RegisterGenerator instead of the Merge method in the CustomLinqToHqlGeneratorsRegistry constructor. My implementation of the CustomLinqToHqlGeneratorsRegistry class is as follows:
public class CustomLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public CustomLinqToHqlGeneratorsRegistry()
: base()
{
MethodInfo toStringMethod = ReflectionHelper.GetMethodDefinition<int>(x => x.ToString());
RegisterGenerator(toStringMethod, new ToStringGenerator());
}
}
There are two, well defined, separate stages here:
Converting the dynamic (string) query into a static expression (done by the Dynamic Linq library)
Parsing that into an HqlTree, then executing (done by NHibernate)
Since you have determined that a static expression works well, the problem lies in 1.
What happens if you do the following?
var results = Enumerable.Empty<Project>().AsQueryable();
string pId = "1";
results = results.Where("Id.ToString().Contains(#0)", pId);
If it fails, you'll have confirmed it's a problem with Dynamic Linq alone (i.e. it doesn't support the expression you're feeding it), so you'll have to dig into it and patch it.
Semi-related: the ToStringGenerator looks useful; could you submit a patch for NHibernate? http://jira.nhforge.org
Supposing the property Id of the class Project it's an Int32 try registering the corresponding Int32.ToString() method in your ToStringGenerator class.
...
public ToStringGenerator()
{
SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition<object>(x => x.ToString()),
ReflectionHelper.GetMethodDefinition<int>(x => x.ToString()),
};
}
...

Expression Tree parsing, variables ends up as constants

So I'm working on a project where I need to parse an expression tree. I got most of the things working, but I've run into a bit of a problem.
I've been looking at the other questions on StackOverflow on Expression Trees, but can't seem to find an answer to my question, so here goes.
My problem is the difference (or lack of) between constants and variables. Let me start off with an example:
user => user.Email == email
This is clearly not a constant but a variable, but this ends up being a ConstantExpression somewhere in the expression tree. If you take a look at the expression itself, it looks a bit odd:
Expression = {value(stORM.Web.Security.User+<>c__DisplayClassa)}
If we take another example:
task => task.Status != TaskStatus.Done && t.Status != TaskStatus.Failed
Here I'm using an ENUM (TaskStatus).
So my problem is that in the tree parsing I seem to end up with a ConstantExpression in both cases, and I really need to be able to tell them apart. These are just examples, so what I'm asking is a generic way of telling these two types of expression from each other, so I can handle then in 2 different ways in my parsing.
EDIT: okay, my examples might not be clear, so I'll try again. First example:
User user = db.Search < User > (u => u.Email == email);
I'm trying to find a user with the given e-mail address. I'm parsing this into a stored procedure, but that's besides the point I guess.
Second example:
IList < Task > tasks = db.Search(t => t.Status != TaskStatus.Done && t.Status != TaskStatus.Failed);
And here I'm trying to locate all tasks with a status different from Done and Failed.
Again this is being parsing into a stored procedure. In the first example my code needs to determine that the stored procedure needs a input parameter, the value of the email variable. In the second example I don't need any input parameters, I just need to create the SQL for selecting task with a status different from Done and Failed.
Thanks again
So from the point of view of expression the value is a constant. It can not be changed by the expression.
What you have is a potentially open closure - i.e. the value can change between executions of the expression, but not during it. So it is a "constant". This is a paradigm difference between the world of functional programming and un-functional :) programming.
Consider
int a =2;
Expression<Func<int, int>> h = x=> x+ a;
Expression<Func<int, int>> j = x => x +2;
a = 1;
the term a is a member access into an anonymous class that wraps up and access the a variable on the stack. The first node is a MemberAccess node then underneath that - the expression is a constant.
For the code above:
((SimpleBinaryExpression)(h.Body)).Right
{value(WindowsFormsApplication6.Form1+<>c__DisplayClass0).a}
CanReduce: false
DebugView: ".Constant<WindowsFormsApplication6.Form1+<>c__DisplayClass0>(WindowsFormsApplication6.Form1+<>c__DisplayClass0).a"
Expression: {value(WindowsFormsApplication6.Form1+<>c__DisplayClass0)}
Member: {Int32 a}
NodeType: MemberAccess
Type: {Name = "Int32" FullName = "System.Int32"}
And the constant underneath that:
((MemberExpression)((SimpleBinaryExpression)(h.Body)).Right).Expression
{value(WindowsFormsApplication6.Form1+<>c__DisplayClass0)}
CanReduce: false
DebugView: ".Constant<WindowsFormsApplication6.Form1+<>c__DisplayClass0>(WindowsFormsApplication6.Form1+<>c__DisplayClass0)"
NodeType: Constant
Type: {Name = "<>c__DisplayClass0" FullName = "WindowsFormsApplication6.Form1+<>c__DisplayClass0"}
Value: {WindowsFormsApplication6.Form1.}
}
}
The plain old 2 comes out to a:
((SimpleBinaryExpression)(j.Body)).Right
{2}
CanReduce: false
DebugView: "2"
NodeType: Constant
Type: {Name = "Int32" FullName = "System.Int32"}
Value: 2
So I don't know if that helps you or not. You can kind of tell by looking at the parent node - or the type of object being accessed by the parent node.
Adding as a result of your clarification -
so when you say
user => user.Email == email
You mean look for all users with an email equal to a passed in parameter - however that link expression means something quite different.
what you want to say is
Expression<Func<User, string, bool>> (user, email) => user.Email == email
This way the email will now be a parameter. If you don't like that there is one other thing you can do.
The second example will work just fine - no extra params are needed consts will be consts.
t => t.Status != TaskStatus.Done && t.Status != TaskStatus.Failed
Edit: adding another way:
So one of the things that you had to do to get your code working was declare a string email outside the lambda - that is kind of clunky.
You could better identify parameters by conventionally putting them in a specific place - like a static class. Then when going through the Lambda you don't have to look at some horrible cloture object - but a nice static class of your making.
public static class Parameter
{
public static T Input<T>(string name)
{
return default(T);
}
}
Then your code looks like this:
Expression<Func<User, bool>> exp = x => x.Email == Parameter.Input<String>("email");
You can then traverse the tree - when you come to a call to to the Parameter static class you can look at the type and the name (in the arguments collection) and off you go....
The name is a bit unfortunate, it is not actually a constant.
It simply refers to a value outside the Expression.
A captured variable (the first case with email) is typically a ConstantExpression representing the capture class instance, with a MemberExpression to a FieldInfo for the "variable" - as if you had:
private class CaptureClass {
public string email;
}
...
var obj = new CaptureClass();
obj.email = "foo#bar.com";
Here, obj is the constant inside the expression.
So: if you see a MemberExpression (of a field) to a ConstantExpression, it is probably a captured variable. You could also check for CompilerGeneratedAttribute on the capture-class...
A literal constant will typically just be a ConstantExpression; in fact, it would be hard to think of a scenario where you use a constant's member, unless you could something like:
() => "abc".Length
but here .Length is a property (not a field), and the string probably doesn't have [CompilerGenerated].
Just check the Type of the ConstantExpression. Any 'constant' ConstantExpression has a primitive type.

Categories