Joining tables dynamically with pure LINQ - c#

I have the following scenario:
There can be two random tables with over 100 columns each.
One of the tables has a foreign key to another.
A user selects a set of columns from both tables, which we should select from db and send back as a JSON object. The restriction is that it should be pure LINQ (not DynamicLINQ).
I tried to play around with expressions by the answers I could find, but the best I've achieved is IEnumerable as result, which is unacceptable, because I need IQueriable to filter it later. I was searching back and forth, but the only working variant I found was on DynamicSQL here, but I'm not allowed to use it.
Any ideas are much appreciated.
Update: As an example, I have two random tables joined by fk, so it's just a regular join, like from t1 in Table1 join t2 in Table2 on t1.field1 = t2.field2. All I need is to be able to pass select expression to this join, built based on collection of strings containing columns I want to select, for example, if I have {"t1.field1", "t1.field2", "t2.field3"}, then the join should look like from t1 in Table1 join t2 in Table2 on t1.field1 = t2.field2 select new {t1.field1, t1.field2, t2.field3}.

The problem with creating instances from a list of columns is that, since .NET is type safe, you will need a type that you can instantiate. When you use anonymous classes (i.e. the new keyword without a class name), the compiler will create a class for you. It's anonymous, but it's still there at compile time (you can check this in a decompiler of yout choice).
If you want to truly be fully dynamic at runtime you will have to dynamically create and compile your classes at execution time. For that you might want to look into the System.CodeDom and the System.Reflection.Emitnamespaces, that both contain classes that allow you to dynamically create types at runtime. That, however, will be quite a massive undertaking, which it doubt will be worth your time. And then you want to access the data in these objects, so you'll probably have to go for dynamic variables.
What should be more feasible is to create a regular class at compile time and instantiate it in your LINQ query. This class would contain all possible properties that you can set. When you instantiate it, you don't have to fill all the fields.
Once you have your class, you can dynamically create expressions that will instantiate it. That's what the classes in the System.Linq.Expressions namespace are for. The Expression class contains factory methods that allow you to create the expression tree you need.
To create your expression tree, you first have to decompose the expression you want to model. Yor expression for the Join would look similar to this (assuming your container class is named DataContainer):
(t1, t2) => new DataContainer {
Value1 = t1.field1,
Value2 = t1.field2,
Value3 = t2.field3
}
This expression has to be split in its parts according to their precedence:
The lambda expression initiated by the lambda operator =>: LambdaExpression, created by Expression.Lambda
The parameters t1 and t2 to the left of the lambda operator: ParameterExpression, created with Expression.Parameter
The object instantiation new DataContainer to the right of the lambda operator: NewExpression, created with Expression.New
The assignments within the initialization block initiated by =: BinaryExpression, created with Expression.Assign
The properties to the left of the assignment: MemberExpression, created with Expression.Property
The property dereferencing with .field1: MemberExpression, created with Expression.Property
The parameter access t1: ParameterExpression, created with Expression.Parameter (but you are reusing the parameter expression you created for the lambda expression)
As you can see, this is quite tedious as compared to just writing down the expression (or using Dynamic LINQ). I will exemplify this with the sub-expression t1.field1:
At this point you will have created the t1 parameter for the left side of the lambda:
ParameterExpression t1Param = Expression.Parameter(typeof(Table1), "t1");
Which you reuse for your property access:
MemberExpression t1field1Property = Expression.Property(t1Param, "field1");
This expression you yan use when you create your assignment, which you will use along with the other assignments in the instantiation expression, which you will use for the right side of your lamdba expression, along with the other needed expressions. You can also write this as a single tree (with the exception of the parameter expressions you are going to reuse).
Happy coding!

Related

Why does a variable value have to be modelled as a member access to the closure in an expression tree?

When I write expressions in our application as lambda expressions, I can usually make use of the following construct1:
dbContext.Contents<MyEntity>()
(dbContext is of a custom class.)
Somehow, Linq1Entities/Entity Framework understands this to mean I am SELECTing items from the table matching MyEntity.
Now, I am constructing an expression by means of the System.Linq.Expressions classes.
I have tried to replicate the above fragment like so:
Expression.Call(Expression.Constant(dbContext), contentsMethod)
contentsMethod has been initialized to the appropriate MethodInfo before by means of reflection.
Unfortunately, this does not work.
Entity Framework complains that it cannot convert the dbContext object to SQL.
I have built an analogous expression of what I wanted as a lambda expression and looked at the resulting expression tree in the debugger.
Interestingly, instead of a constant, the dbContext was modeled as a member access of what seemed to be a closure object.
Why is that? Why is a local variable dbContext represented by a member access to the closure in an expression, and why doesn't it alternatively work as a constant value? Does it matter that dbContext was a parameter of the enclosing method in my case?
My question is not how to solve the issue.
I already did, by introducing the fragment shown above as an extra lambda expression whose body gets tied into my manually built expression.
1: An example of how that fragment is used is the following expression:
dbContext.Contents<MyEntity1>().Where(e1 => dbContext.Contents<MyEntity2>().Any(e2 => e1.Name == e2.Key))
dbContext is modeled as an access to a closure object because the lambda that defined it was closing over that variable. It wasn't using a constant value, it was closing over another value, so that's what it represented in the Expression. If it did anything else it wouldn't be properly representing the lambda.
When EF says that it can't convert an Expression to SQL it's simply saying that the authors of the code didn't anticipate the given expression, and didn't create a mapping of that pattern to SQL; they simply didn't anticipate people doing this (or didn't know how to map it to SQL, or couldn't, or didn't have the time to add that feature, whatever the case may be).

Build linq groupby expression dynamically with nested property from string

I use nhibernate mapping by code, I want to make this expression dynamicllay (with a nested object)
I have a class event that has a relation many to one with Event state/and I want to grouping by code in the table EventState
var grouping = query.GroupBy(x => x.EventState.Code)
It works for me with a simple property, here is my code:
var arg = Expression.Parameter(type, categoryColumnName);
var bodyy = Expression.Convert(Expression.Property(arg, categoryColumnName), typeof (object));
var lambdaGroupBy = Expression.Lambda<Func<Operation, object>>(bodyy, arg);
var keySelector = lambdaGroupBy.Compile();
var grouping = query.GroupBy(keySelector);
return grouping.Select(a => new PieChartObject { Category = a.Key.ToString(), Value = a.Count().ToString() }).ToList();
But I can't do it with nested object.
GroupBy will partition your query by what you provide as key selector. To determine whether two items in your query have the same key, it uses the default comparer of the given type. For object, this is uses the Equals and GetHashCode methods which in turn for strings mean that the contents of the strings are identical. If you use a class, by default the reference identity is used, so I think that GroupBy isn't doing anything in your case because the keys you provided are not identical, even though they may have the same values.
So there are two valid solutions: You can either override Equals and GetHashCode in your nested object class, or you can provide a custom key comparer to GroupBy, if you want this behavior only for this particular query. But I guess, as you want to be generic, implementing Equals and GetHashCode would be a better option. The only exception is of course when you cannot do this, e.g. because it is a compiler-generated class. In that case, there is few things you can do about that.

Understanding two methods with LINQ and lambda

I have a question, my friend and I are doing code, and he did two methods that I don't exactly understands.
public static List<Borrow> GetDistinctBorrows(List<Borrow> list)
{
var Result = (from bor in list group bor by new { bor.BookAccessor, bor.ReaderAccessor } into dist select dist.First()).ToList();
return Result;
}
and a second one
public static List<Borrow> GetDistinctBorrows(List<Borrow> list)
{
var Result = list.GroupBy(x => new { x.ReaderAccessor, x.BookAccessor }).Select(y => y.First()).ToList();
return Result;
}
Those methods have the same functionality, but one are written with LINQ, and a second one with lambda expressions.
Can someone explain to me, how they work (especially the fragment with 'new' word)?
The part with new word is how you define instances on Anonymous Types.
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at the source code level. The type of each property is inferred by the compiler.
You create anonymous types by using the new operator together with an object initializer. For more information about object initializers, see Object and Collection Initializers (C# Programming Guide).
As a side note, your queries are equivalent, because compiler will transform the first one onto the second one as part of compilation process. Read more about that on MSDN: Query Syntax and Method Syntax in LINQ (C#)
Most queries in the introductory Language Integrated Query (LINQ) documentation are written by using the LINQ declarative query syntax. However, the query syntax must be translated into method calls for the .NET common language runtime (CLR) when the code is compiled. These method calls invoke the standard query operators, which have names such as Where, Select, GroupBy, Join, Max, and Average. You can call them directly by using method syntax instead of query syntax.
The functions gets a list of distinct items from the input list, where ReaderAccessor and BookAccessor determine equality. Duplicated items from the input list is discarded.
They work by grouping by a new anonymous object defined by the two properties (this is where the new keyword is used), creates an alias dist and then taking the first one, essentially discarding the rest.

Trying to understand what an expression tree is

Both snippets below product the same output.
I understand how Func encapsulates a method with a single parameter, and returns a bool value. And you can either assign it a
method, anonymous method or a lambda expression.
Func<int, bool> deleg = i => i < 5;
Console.WriteLine("deleg(4) = {0}", deleg(4));
Below is using expression trees which I don't fully understand yet. Why would I want to do it this way? Is it more flexible, what advantage does it give me?
System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;
Func<int, bool> deleg2 = expr.Compile();
Console.WriteLine("deleg2(4) = {0}", deleg2(4));
Basically, the Expression tree is the body of a lambda expression, that allows you to
introspect the expression (see what's in it so to say)
manipulate the expression (simplify, extend (e.g. add new functionality or modify to work on different items).
Once you Compile() the expression, it is just another delegate, which you can only call, not inspect or modify.
Whenever you want to
create expressions dynamically (I mean: construct, not allocate)
operate on expressions dynamically
the Function<> types are not sufficient.
The point of expression trees is that you can do more with them than just compile them to a function. You can inspect them, modify them and compile them to something other than .net functions.
For example Linq2SQL compiles expression trees to SQL code. You couldn't do that with a plain .net function.
In your first example you just have "hardcoded" the body of the function and assigned it to a delegate.
In your second example the assignment constructs an expression-tree which is an object model reprensenting your code in a data structure in memory.
The advantage is that you can modify and inspect that datastructure.
LINQ2SQL for example uses that technique to translate your expressions to another language called SQL.
Expression trees are regular in-memory data structures that can be traversed programmatically and the result of such traversal can be something, like a query you'd like to send to the database. Read more on the ExpressionVisitor class to see how it is done.
On the other hand, the compiled function is nothing more than a sequence of CIL code. You still can inspect it programmatically but you are not inspecting the definition but rather - the compiler output of it.

Dynamically query an object set in EF using LambdaExpression

I am trying to dynamically query Entity Framework, so I'm using the Expression class to put together a LambdaExpression that will be queried against an object set. If I have a reference to LambdaExpression, where I don't have an explicit function defined, is it possible to query against an objectset this way, or is it required to have a generic expression defined (using Expression.Lambda<..>)?
Thanks.
This is what I was looking to do:
http://msdn.microsoft.com/en-us/library/bb882637.aspx
Using this, I was able to build a lambda expression against an object set dynamically. Worked very well.
Check out Dynamic Linq. Basically you can use strings in place of LINQ expressions until you want to use them. Sounds like it might be what you want.

Categories

Resources