If anyone is very familar with the Linq.Dynamic namespace I could use some help -- couldn't find any indepth resources on the internet.
Basically I'm using DynamicExpression.ParseLambda to create an expression where the type is not known at compile time,
public Expression GetExpression(Type t, List<QueryFilter> filters)
{
// pseudo code
// extracts a string representation of the query as 'expressionString'
return DynamicExpression.ParseLambda(t, typeof(Boolean), expressionString, values);
}
Where a QueryFilter is:
public class QueryFilter
{
string propertyName;
ExpressionType operationType;
object value;
}
Which represents a simple binary function like "Age > 15" or something.
This is how the 'GetExpression' function works, it takes 2 types -- one that is the input type and one that is the output type, and ultimately generates what would normally be created with a Func delegate. It also takes a string that represents the query and a params object[] of values, which are 'expressionString' and 'values' above, respectively.
However I am having trouble executing the dynamic expression in LINQ-to-SQL, using a DataContext generated from SqlMetal (.dbmc file).
DatabaseContext db = new DatabaseContext(connectionString);
var filter = DynamicExpressionBuilder.
GetExpression(typeof(SysEventLogT), sysEventFilters)
var query = db.SysEventLogT.Where(filter);
Produces the following error,
System.Data.Linq.Table<DBReporting.Linq.Data.SysEventLogT>
does not contain a definition for 'Where' and the best extension method overload
System.Linq.Dynamic.DynamicQueryable.Where<T>(System.Linq.IQueryable<T>, string, params object[])
has some invalid arguments.
I know that my DataContext instance actually treats the sql tables as properties...do I need to reflect with GetProperty() somehow for this to work? Or perhaps I need to create another .Where extension?
Your GetExpression is returning an Expression type - the DynamicQueryable.Where method, when used as an extension method, expects a string as the first parameter.
You need your call to Where to look like this:
var query = db.SysEventLogT.Where("Age > #0", 15);
Also, you could try the following, just to be explicit:
var query = db.SysEventLogT.AsQueryable().Where("Age > #0", 15);
Note that if easier, you can build a sting containing the full filter and not use the params object[] parameter at all:
var query = db.SysEventLogT.AsQueryable().Where("Age > 15");
Related
I would like to create the following expression dynamically:
e.Collection.Select(inner => inner.Property)
I created this code to do it, however I have an issue when I execute the expression call, someone knows what I'm doing wrong?
private static Expression InnerSelect<TInnerModel>(IQueryable source, ParameterExpression externalParameter, string complexProperty)
{
// Creates the expression to the external property. // this generates: "e.Collection".
var externalPropertyExpression = Expression.Property(externalParameter, complexProperty);
// Creates the expression to the internal property. // this generates: "inner => inner.Property"
var innerParameter = Expression.Parameter(typeof(TInnerModel), "inner");
var innerPropertyExpression = Expression.Property(innerParameter, "Property");
var innerLambda = Expression.Lambda(innerPropertyExpression, innerParameter);
return Expression.Call(typeof(Queryable), "Select", new [] { typeof(TInnerModel) }, externalPropertyExpression, innerLambda);
}
Error:
No generic method 'Select' on type 'System.Linq.Queryable' is
compatible with the supplied type arguments and arguments. No type
arguments should be provided if the method is non-generic.
So, first off, the primary problem is very simple. As the error message says, you haven't passed enough type arguments to Select. But when you fix that, you'll still have a problem, and that problem will be much harder for you to see and understand.
Let's dig into that.
You wish to represent this as an expression tree:
e.Collection.Select(inner => inner.Property)
Let's begin by rewriting it in its non-extension-method form.
Queryable.Select<A, B>(e.Collection, inner => inner.Property)
Where A is the collection member type and B is the type of Property.
Now, suppose you had this expression in your program. What would it actually do at runtime? It would construct an expression tree for the lambda and pass it to Queryable.Select. That is, it would do something like:
var innerParameter = parameterFactory(whatever);
var lambdaBody = bodyFactory(whatever);
var lambda = makeALambda(lambdaBody, innerParameter);
Queryable.Select<TInnerModel>(e.Collection, lambda);
Right? You with me so far?
Now, suppose we wish to translate this program fragment to an expression tree that could itself be the body of a lambda. That would be:
var theMethodInfoForSelect = whatever;
var receiverE = valueFactory(whatever);
var thePropertyInfoForCollection = whatever;
var theFirstArgument = propertyFactory(receiverE, thePropertyInfoForCollection);
...
Again, with me so far? Now, the crucial question: what is the second argument? It is NOT the value of lambda, which is what you are passing. Remember, what we are doing here is constructing an expression tree which represents the code that the compiler is generating for that thing, and the expression tree that is in lambda is not that. You're mixing levels!
Let me put it this way: the compiler is expecting "add one and three". You are passing 4. Those are very different things! One of them is a description of how to obtain a number and the other one is a number. You are passing an expression tree. What the compiler is expecting is a description of how to obtain an expression tree.
So: do you have to now write code that generates expression trees for all of lambda's construction code? Thank goodness no. We provided you a handy way to turn an expression tree into a description of how to produce an expression tree, which is the Quote operation. You need to use it.
So, what is the right sequence of events that you need to do to build your expression tree? Let's walk through it:
First, you'll need a ParameterExpression of the type of e, which you already have in hand. Let's suppose that is:
ParameterExpression eParam = Expression.Parameter(typeof(E), "e");
Next, you will need a method info for the Select method. Let's suppose you can correctly get that.
MethodInfo selectMethod = whatever;
That method takes two arguments, so let's make an array of argument expressions:
Expression[] arguments = new Expression[2];
You'll need a property info for your Collection property. I assume you can get that:
MethodInfo collectionGetter = whatever;
Now we can build the property expression:
arguments[0] = Expression.Property(eParam, collectionGetter);
Super. Next we need to start building that lambda. We need a parameter info for inner:
ParameterExpression innerParam = Expression.Parameter(typeof(Whatever), "inner");
We'll need a property info for Property, which I assume you can get:
MethodInfo propertyGetter = whatever;
Now we can build the body of the lambda:
MemberExpression body = Expression.Property(innerParam, propertyGetter);
The lambda takes an array of parameters:
ParameterExpression[] innerParams = { innerParam };
Build the lambda from the body and the parameters:
var lambda = Expression.Lambda<Func<X, int>>(body, innerParams);
Now the step you missed. The second argument is the quoted lambda, not the lambda:
arguments[1] = Expression.Quote(lambda);
Now we can build the call to Select:
MethodCallExpression callSelect = Expression.Call(null, selectMethod, arguments);
And we're done.
Give someone an expression tree and you give them an expression tree for a day; teach them how to find expression trees themselves and they can do it for a lifetime. How did I do that so fast?
Since I wrote the expression tree code generator, I had some immediate familiarity with the problem that you were likely to have. But that was ten years ago, and I did not do the above entirely from memory. What I did was I wrote this program:
using System;
using System.Linq.Expressions;
public interface IQ<T> {}
public class E
{
public IQ<X> C { get; set; }
}
public class X
{
public int P { get; set; }
}
public class Program
{
public static IQ<R> S<T, R>(IQ<T> q, Expression<Func<T, R>> f) { return null; }
public static void Main()
{
Expression<Func<E, IQ<int>>> f = e => S<X, int>(e.C, c => c.P);
}
}
Now I wished to know what code was generated by the compiler for the body of the outer lambda, so I went to https://sharplab.io/, pasted in the code, and then clicked on Results --> Decompile C#, which will compile the code to IL and then decompile it back to human-readable C#.
This is the best way I know of to quickly understand what the C# compiler is doing when it builds an expression tree, regardless of whether you know the compiler source code backwards and forwards. It's a very handy tool.
So, I am trying to learn how to put together my own expressions, pass objects and compile to retrieve generated result, and I am stuck trying to understand exactly where my object instance goes in all of this.
So this is what I have gotten so far from reading through the code and stepping through
Create your object instance, your expressionstring, and parameters.
T SampleString = "Some String I have";
var operation= "it.Replace(#0, #1)";
var operationParameters = new [] { "e", "CLOWN"};
Create a ParameterExpression object to specify the type of parameter your operation will be performed on
ParameterExpression[] parameters = new ParameterExpression[] { Expression.Parameter(typeof(T), "") };
Using the ExpressionParser class, create the expression you need to be executed against your object there
ExpressionParser parser = new ExpressionParser(parameters, operation, operationParameters );
Called the ExpressionParser Parse method to retrieve the generated Expression, passing it the type of the result you want
var generatedExpression = parser.Parse(typeof(String));
Now call the Expression.Lamba, passing it the generatedExpression, and the item
var StringReplaceresult = Expression.Lambda<Func<T,String> >(generatedExpression , parameters).Compile()(item);
I am not quite sure if the above is correct, or where exactly the issue I am having with it starts. I do know that my Compile fails (5). The message is about not passing in the right number of parameters to the Expression.Lamba method there. But I wonder if that is really where the problem is as, again, I am not sure I get this even 60%, so I would appreciate it is someone would please correct my work above, where necessary.
I'm assuming you're using the Dynamic Linq Query Library described by Scott Guthrie:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
If so, I think you want:
string sampleString = "some string I have";
var operation= "it.Replace(#0, #1)";
var operationParameters = new [] { "e", "CLOWN"};
Expression<Func<string, string>> expr = DynamicExpression.ParseLambda<string, string>(operation, operationParameters);
string result = expr.Compile().Invoke(sampleString);
When I run this in LinqPad the value of result is "somCLOWN string I havCLOWN"
The DynamicExpression.ParseLambda allows you to specify the parameter types as generic type arguments, rather than doing it by explicit creation of a ParameterExpression array as you were doing.
The ParseLambda<> call returns a strongly typed Expression<TDelegate> object and it's Compile() method compiles the underlying lambda expression into executable code and returns it as a delegate of the correct type that can then be invoked. That means the Invoke() returns an object of the correct type(string in this case) rather than an object that has to be cast. So even though you start off with non-strongly-typed code, you get back to type-safety as quickly as possible.
http://msdn.microsoft.com/en-us/library/bb345362.aspx
p.s.
And in the source code I have, ExpressionParser is internal, you naughty boy/girl ;o)
I have a class (SearchParameters) that holds search parameters, i then create a linq query based on these using a generic class called Querybuilder. This returns the results and all works perfectly.
The results are displayed in GridView, i am currently implementing custom sorting for the gridivew, I add the field to be searched to the SearchParameters object (using a fluent interface)
SearchParameters=SearchParameters.SortResultsBy(e.SortExpression,e.NewSortOrder.ToString());
I need the datatype of the columns to be used as a generic parameter to my AddOrderByClause() method:
public void AddOrderByClause<D>(string field, Type sourceDateType)
{
var orderExpression = Expression.Lambda<Func<T, D>>(Expression.Property(resultExpression, field), resultExpression);
rootExpression = Expression.Call(
typeof(Queryable),
"OrderBy",
new Type[] { typeof(T), typeof(D) },
rootExpression,
orderExpression);
}
I can easily find the data type of the columns, but how do i pass it to the AddOrderByClause() (generic parameter D)?
public void AddOrderByClause<D,E>(string field, E sourceDataType)
{
.....
}
Use reflection to get the method AddOrderByClause, then use MakeGenericMethod to get the generic. This is the general idea (a bit vague because I don't know what all your types are named).
Type MyTypeParameter; // TODO set this to type parameter D
Type type; // TODO set this to the type that contains the method "AddOrderByClause"
MethodInfo method = type.GetMethod("AddOrderByClause");
MethodInfo genericMethod = method.MakeGenericMethod(typeof(MyTypeParameter));
genericMethod.Invoke(MyClassInstance, FieldParam, SourceDataParam);
but how do i pass it to the AddOrderByClause() (generic parameter D)?
Seems like you already have datatype of the columns, and you figuring out how to pass it to Generic method
Below is example
First modify AddOrderByClause to accept T (used later in your function)
public void AddOrderByClause<D,T>(String field)
{
....
}
Then call AddOrderByClause like
var data = SearchParameter;// Use actual data if SearchParameter is not correct
AddOrderByClause<D,date.GetType()>(fieldData);// assuming fieldData is something different
var data = SearchParameter;// Use actual data if SearchParameter is not currect
I have a linq query written in method syntax. I need to create a very similar method with just some changes to the final Select.
Is it possible to return the partial Linq query from a method so I dont duplicate the code? The issue I have is finding the "Type" of the query to mark the method with.
If I use query.GetType(), it returns (cut down version) :
SubSonic.Linq.Structure.Query`1[<>f__AnonymousType18`6[advert,client]]
I tried to create a return type:
SubSonic.Linq.Structure.Query<advert, client> query = new SubSonic.Linq.Structure.Query<advert, client>();
However I receive the error:
Error 20 Using the generic type 'SubSonic.Linq.Structure.Query<T>' requires '1' type arguments
So I guess I am asking how to declare a return type that is a Subsonic Query containing an anonymous type containing a number of objects? (2 in my example)
Please excuse my simple example:
eg:
internal ????? GetQueryBody(string param1, string param2){
/* buld the linq query here */
}
internal List<Booking> GetSearchResultsOne(string param1, string param2){
var query = this.GetQueryBody(string param1, string param2);
var res = query.Select( db => new Booking { /*fields */).ToList();
return res;
}
internal List<BookingData> GetSearchResultsTwo(string param1, string param2){
var query = this.GetQueryBody(string param1, string param2);
var res = query.Select( db => new BookingData { /*fields*/).ToList();
return res;
}
Thank you for your time,
Yohimbo
Use IEnumerable<T> to return a query.
About the anonymous type: If a type is anonymous, how should another methode know about it? Read more here. To solve the problem, give your anonymous type a name by creating a class.
If you only want to return two types you could also return a tuple: Then T is Tuple<advert,client>. You can create a tuple by
var t = new Tuple<advert,client>(client, advert);
Answer 1: You can't do it because Booking and BookingData are different types so the expression trees are different.
Answer 2: Assuming you can find a common base class, there are two approaches to your question.
The 'type' of what a Linq Query acts on is actually an Expression<TDelegate>. You can construct Expression trees and store them and manipulate them, and then use them where needed.
The 'argument' for your final Select() is actually an Expression<Func<TSource, TResult>>. You can use any function in that location as long as it conforms to that delegate.
In other words, you can store the entire pre-formed expression trees from the top, or you can store one tree and substitute the bit at the bottom. There isn't enough in your sample for me to write the code, and you still have to resolve that fatal flaw.
I'm trying to create a generic extension method, that works on typed data tables :
public static class Extensions
{
public static TableType DoSomething<TableType, RowType>(this TableType table, param Expression<Func<RowType, bool>>[] predicates)
where TableType : TypedTableBase<RowType>
where RowType : DataRow
{
// do something to each row of the table where the row matches the predicates
return table;
}
[STAThread]
public static void main()
{
MyTypedDataSet.MyTypedDataTable table = getDefaultTable();
}
public static MyTypedDataSet.MyTypedDataTable getDefaultTable()
{
// this line compiles fine and does what I want:
return new MyTypedDataSet.MyTypedDataTable().DoSomething<MyTypedDataSet.MyTypedDataTable, MyTypedDataSet.MyTypedRow>(row => row.Field1 == "foo");
// this line doesn't compile :
return new MyTypedDataSet.MyTypedDataTable().DoSomething(row => row.Field1 == "foo");
// Error : The type arguments .. cannot be inferred from the usage
}
}
The first line works fine, but it's really ugly...
The second line doesn't compile because the compiler cannot infer the type of RowType.
This is a method that will be used as part of a DataLayer by many different programmers, so I would rather not need them to specify the TypeParameter.
Shouldn't the compiler know that RowType is the same type as the one that was used by TypedTableBase ?
For different reasons that may not be obvious in this code sample, I really need to return the datatable in its original form. And the reason I need RowType is so the 'Expression<Func<T, bool>>' will be typed and seen by InteliSence.
Thanks
Method type inference does not make inferences from arguments to constraints. It makes inferences from arguments to formal parameters and then checks whether the inferences made from the arguments to the formals satisfy the constraints.
In your case there is not enough data from the arguments to deduce what the type parameters are without first looking at the constraints, which we're not going to do until we check the inferences against the constraints. Sorry about that, but that's how the type inference algorithm is specified.
I've been asked questions about this many times and the consensus seems to be that I am morally wrong for maintaining the position that inference should infer from arguments to formal parameters alone. For about a dozen people telling me I'm wrongheaded in this regard, see the comments to my analysis of this closely related issue:
http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx
I maintain my position.
Eric's answer is great for explaining why the types cannot be inferred. Here are a couple of suggestions to hopefully cut down on the verbosity of the code that you will have to write.
If you can explicitly define the type of your lambda expression, then it can infer the types.
One example of how to do that is below. I've created a criteria parameter that is explicitly of type Expression<Func<MyTypedDataSet.MyTypedRow, bool>>. In this example, this doesn't save you much typing, but perhaps in practice you can make use of this.
MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable();
Expression<Func<MyTypedDataSet.MyTypedRow, bool>> criteria = row => row.Field1 == "foo";
return table.DoSomething(criteria);
EDIT: altered my example to use another extension method rather than deriving a custom TypedTableBase<T> class from System.Data.TypedTableBase<T>.
Below is another example that can do a better job of inferring the type parameters. You define another extension method (mine is called RowPredicate) that only has one type parameter to infer. The first parameter is of type TypedTableBase<RowType>, so the compiler should have no problem inferring the type from that:
public static Expression<Func<RowType, bool>> RowPredicate<RowType>(this TypedTableBase<RowType> table, Expression<Func<RowType, bool>> predicate)
where RowType : DataRow
{
return predicate;
}
This allows you to compile the following code:
MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable();
return table.DoSomething(table.RowPredicate(row => row.Field1 == "foo"));
Primarily the table parameter simply servers to inform the compiler of the type to use for RowType. Is this a good idea? I'm not so sure, but it does allow the compiler to infer all of the generic types.
Even if that wasn't ideal, I gave up trying to return anything at all which allows me to do something like the following:
public static void DoSomething<RowType>(this TypedTableBase<RowType> table, param Expression<Func<RowType, bool>>[] predicates)
where RowType : DataRow
{
// do something to each row of the table where the row matches the predicates
// do not return the table... too bad for chaining commands
}
And then use it like so:
MyTypedDataSet.MyTypedDataTable table = new MyTypedDataSet.MyTypedDataTable();
table.DoSomething(row => row.Field1 == "foo"));
and the compiler infers the type correctly.
Thank you both for your answers.