I am somewhat new to expression trees and I just don't quite understand some things.
What I need to do is send in a list of values and select the columns for an entity from those values. So I would make a call something like this:
DATASTORE<Contact> dst = new DATASTORE<Contact>();//DATASTORE is implemented below.
List<string> lColumns = new List<string>() { "ID", "NAME" };//List of columns
dst.SelectColumns(lColumns);//Selection Command
I want that to be translated into code like this (Contact
is an entity using the EF4):
Contact.Select(i => new Contact { ID = i.ID, NAME = i.NAME });
So let's say I have the following code:
public Class<t> DATASTORE where t : EntityObject
{
public Expression<Func<t, t>> SelectColumns(List<string> columns)
{
ParameterExpression i = Expression.Parameter(typeof(t), "i");
List<MemberBinding> bindings = new List<MemberBinding>();
foreach (PropertyInfo propinfo in typeof(t).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (columns.Contains(propinfo.Name))
{
MemberBinding binding = Expression.Bind(propinfo, Expression.Property(i, propinfo.Name));
bindings.Add(binding);
}
}
Expression expMemberInit = Expression.MemberInit(Expression.New(typeof(t)), bindings);
return Expression.Lambda<Func<t, t>>(expMemberInit, i);
}
When I ran the above code I got the following error:
The entity or complex type 'Contact' cannot be constructed in a LINQ to Entities query.
I looked at the body of the query and it emitted the following code:
{i => new Contact() {ID = i.ID, NAME = i.NAME}}
I am pretty sure that I should be able to construct the a new entity because I wrote this line explicitly as a test to see if this could be done:
.Select(i => new Contact{ ID = i.ID, NAME = i.NAME })
This worked, but I need to construct the select dynamically.
I tried decompiling a straight query(first time I have looked at the low level code) and I can't quite translate it. The high level code that I entered is:
Expression<Func<Contact, Contact>> expression = z =>
new Contact { ID = z.ID, NAME = z.NAME };
Changing the framework used in the decompiler I get this code:
ParameterExpression expression2;
Expression<Func<Contact, Contact>> expression =
Expression.Lambda<Func<Contact, Contact>>
(Expression.MemberInit(Expression.New((ConstructorInfo) methodof(Contact..ctor),
new Expression[0]), new MemberBinding[] { Expression.Bind((MethodInfo)
methodof(Contact.set_ID), Expression.Property(expression2 = Expression.Parameter(typeof(Contact), "z"), (MethodInfo)
methodof(Contact.get_ID))), Expression.Bind((MethodInfo)
methodof(Contact.set_NAME), Expression.Property(expression2, (MethodInfo)
methodof(Contact.get_NAME))) }), new ParameterExpression[] { expression2
});
I have looked several places to try and understand this but I haven't quite gotten it yet. Can anyone help?
These are some places that I have looked:
- msdn blog -- This is exactly what I want to do but my decopiled code soes not have Expression.Call.
- msdn MemberInit
- msdn Expression Property
- stackoverflow EF only get specific columns -- This is close but this seems like it is doing the same thing as if i just use a select off of a query.
- stackoverflow lambda expressions to be used in select query -- The answer here is exactly what I want to do, I just don't understand how to translate the decompiled code to C#.