In the following code, the type of domainObject
varies (but ends with DO
, which I trim then to get the corresponding table name). Having the name of the table and its type, I want to update an existing object - its name is the same as the tableName
due to the EF - in the database with the new property values from domainObject
. Therefore, I have to find the POCO in the table with the same ID
first to overwrite this. This is the code so far:
public void Update(object domainObject)
{
Type type = domainObject.GetType();
string tableName = type.Name.Substring(0, type.Name.Length - 2);
PropertyInfo tableProp = typeof(MyDbContext).GetProperty(tableName);
Type tableType = tableProp.PropertyType;
Type pocoType = tableType.GetGenericArguments()[0];
int id = (int)type.GetProperty("ID").GetValue(domainObject);
using (var context = new MyDbContext())
{
object table = tableProp.GetValue(context);
MethodInfo singleMethod = tableType.GetMethod("Single");
}
}
Usually, knowing the actual table and not just its type, I would now get the POCO via
var poco = context.TableName.Single(item => item.ID == id);
There's 2 problems here:
(1) Single
is an extension method.
(2) I don't have an idea how to get the lambda expression in form of an object
to pass it to the Invoke
of Single
.
Is there any way to do this at all with Reflection, or do I have to work around this? (For example, I could iterate through the items in table
and check manually [which would load everything from the DB into memory and thus should be avoided], or maybe configure the EF to do some kind of 'override' whenever I just Add
and object whose ID
is already present if this is possible). Even supposing I could work around this, I'd still like to know a definitive answer to this question, since it's pretty interesting for me!
If you want to use reflection and to find given entity by ID then, if ID is primary key this is fairly simple as this is all you have to do:
object entity = context.Set(domainObject.GetType()).Find(id);
If your property is not primary key then you need to do it as follows:
ParameterExpression p = Expression.Parameter(domainObject.GetType());
Expression property = Expression.Property(p, "ID");
Expression c = Expression.Constant(id);
Expression body = Expression.Equal(property, c);
Expression exp = Expression.Lambda(body, new ParameterExpression []{ p });
MethodInfo singleMethod = typeof(Queryable).GetMethods()
.Single(m => m.Name == "Single" && m.GetParameters().Count() == 2)
.MakeGenericMethod(domainObject.GetType());
DbSet dbSet = context.Set(domainObject.GetType());
object entity = singleMethod.Invoke(null, new object[]{ dbSet, exp });
First with Expression
class you build expression that will be passed to Single
method (in your case this will be p => p.ID == id
). Then you search proper Single
method from Queryable
class. The last thing is to invoke this method with proper parameters. This way you may do any linq queries with use of Reflection
.