动态和高效的调用在DbSet上添加方法

时间:2011-10-24 06:56:31

标签: c# entity-framework

我想对DbSet上的Add方法进行动态调用,我在编译时不知道。

实际上,它可以通过简单的反射,但性能很糟糕。这是我们现在使用的代码:

Type contextType = (context as Object).GetType();
var set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod("Add");

Object[] args = { entity };

method.Invokke(set, args);

我尝试了另外两种不同错误的可能性。

第一个是使用委托

public delegate void MyDel<T>(T t,object entity);

Type contextType = (context as Object).GetType();
var set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod("Add");

Type template = typeof(MyDel<>);
Type specific = template.MakeGenericType(childClassType);
Delegate test = Delegate.CreateDelegate(specific, method);

但是在最后一行,我收到以下错误:绑定到目标方法的错误

第三个选项是使用这样的表达式树:

Type contextType = (context as Object).GetType();
var set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod("Add");


ParameterExpression paramo = Expression.Parameter(typeSet, "param");
ParameterExpression parami = Expression.Parameter(typeSet, "newvalue");
Expression convertedParamo = Expression.Convert(paramo, typeof(Object));
Expression convertedParami = Expression.Convert(parami, typeof(Object));

MethodCallExpression methodCall = Expression.Call(convertedParamo, method, convertedParami);                    

Expression valueExp = Expression.Lambda(methodCall, paramo, parami);
Expression<Action<Object, Object>> dynamicExpression = (Expression<Action<Object, Object>>)valueExp;
Action<Object, Object> dynamicAction = dynamicExpression.Compile();

Object o = Activator.CreateInstance(otherType);
dynamicAction(o, entity);

但是在这种情况下,在“Expression.Call(convertedParamo,method,..

”这一行

我收到了这个错误:

  

方法'DictionnaireONYX.Entites.ArticleSansFacturier   添加(DictionnaireONYX.Entites.ArticleSansFacturier)'在类型上声明   'System.Data.Entity.DbSet`1 [DictionnaireONYX.Entites.ArticleSansFacturier]'   不能使用'System.Object'

类型的实例调用

其中ArticleSansFacturier是DbSet。

谁能帮帮我?

提前致谢

2 个答案:

答案 0 :(得分:0)

我不得不说我现在不知道性能如何,但在对代码进行一些更改后,它似乎有效。特别是最后的动态部分可能会带来一些问题。

我使用了ModelContext并在其中设置了作者。

ModelContext context = new ModelContext();

Author entity = new Author();

string entitySetName = "Authors";
string methodName = "AddObject";

Type contextType = (context as Object).GetType();
var set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod(methodName);

ParameterExpression paramo = Expression.Parameter(typeSet, "param");
ParameterExpression parami = Expression.Parameter(entity.GetType(), "newvalue");

MethodCallExpression methodCall = Expression.Call(paramo, method, parami);

Type typeofClassWithGenericStaticMethod = typeof(Expression);
MethodInfo methodInfo = typeofClassWithGenericStaticMethod.GetMethods().Where(m => m.Name == "Lambda" && m.IsGenericMethod).First();
Type genericArguments = typeof(Action<,>).MakeGenericType(typeSet, entity.GetType());
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);

dynamic objectSet = set;
dynamic returnValue = genericMethodInfo.Invoke(null, new object[] { methodCall, new ParameterExpression[] { paramo, parami } });
var action = returnValue.Compile();

action(objectSet, entity);

答案 1 :(得分:0)

如果您使用的是.NET 4.0,则可以使用“dynamic”关键字 - 这是最好,最高效的方式。 它看起来像这样:

Type contextType = (context as Object).GetType();
dynamic set = (contextType.GetProperty(entitySetName)).GetValue(context, null);
set.Add(args);

我不确定我100%理解你的代码,所以不确定这正是你想要做的,但这是一般的想法。

进一步阅读: http://msdn.microsoft.com/en-us/library/dd264736.aspx