【问题标题】:Invoking DbSet<Type>.Add() method using reflections, in a child class of DbContext在 DbContext 的子类中使用反射调用 DbSet<Type>.Add() 方法
【发布时间】:2015-12-03 14:35:29
【问题描述】:

我有一个通过实体框架与数据库对话的 DbContext 子类。我正在使用 MVC C#。

我有 n 个与我的表相关的 DbSet。我想为任何 DbSet.Add(entityObject) 调用 Add 方法,在这种情况下 UserAccounts.Add(entityUserAccount) 使用反射或动态变量。

我这样做是因为我需要在我的控制器中通过依赖注入来注入 DbContect。

public class DataContext: DbContext
{
     public DbSet<UserAccount> UserAccounts { get; set; }

     public void Insert<TypeEntity>(TypeEntity entity) where TypeEntity : BaseEntity
     {
        var typesToRegister = typeof(DataContext).GetProperties().
                     Where(p => p.PropertyType == typeof(DbSet<TypeEntity>));

        //This is where the code explodes in face:-)
        //Please let me know how to fix it
        var dbSetItem = typesToRegister.First();
        var methodAdd = dbSetItem.GetType().GetMethod("Add");
        methodAdd.Invoke(this, new TypeEntity[] { entity });
     }
}


//Insert<TypeEntity>(TypeEntity entity) is my service 
//method to invoke the DbSet<T>.Add() method.

这是我得到的错误:对象引用未设置为对象的实例。

【问题讨论】:

  • 那么,代码有什么问题?

标签: c# entity-framework dynamic reflection dbcontext


【解决方案1】:

我修复了你的代码。有两个错误:

  1. 而不是

var methodAdd = dbSetItem.GetType().GetMethod("Add");

你应该写:(因为 dbSetItem.GetType() 将返回 propertyType 而不是你所期望的字段类型)

dbSetItem.GetValue(this).GetType().GetMethod("Add");

  1. 并更改此行(因为应该以这种方式调用 Add 方法:db.Items.Add(...) 而不是 db.Add(...))

methodAdd.Invoke(this, new TypeEntity[] { entity> });

到那个人:

methodAdd.Invoke(dbSetItem.GetValue(this), new TypeEntity[] { entity> });

您是否忘记在代码末尾调用 SaveChanges 方法?

    public void Insert<TypeEntity>(TypeEntity entity) where TypeEntity: BaseEntity
    {
        var typesToRegister = typeof(DataContext).GetProperties().
                     Where(p => p.PropertyType == typeof(DbSet<TypeEntity>));

        var dbSetItem = typesToRegister.First();

        var methodAdd = dbSetItem.GetValue(this).GetType().GetMethod("Add");
        methodAdd.Invoke(dbSetItem.GetValue(this), new TypeEntity[] { entity });
        SaveChanges();
    }

【讨论】:

  • 请详细说明更改的内容和原因。这样我们都可以学到一些东西。
【解决方案2】:

dbSetItem 的类型为 PropertyInfo,因为您调用了 GetProperties()。它没有Add 方法,这就是为什么你会得到null(如果找不到匹配的方法,GetMethod 返回null)。

var dbSetItem = typesToRegister.First().PropertyType;

你不能将this传递给Invoke的第一个参数,它必须是DbSet&lt;TypeEntity&gt;类型的对象,你的数组也应该是object[](你可以传递别的东西,因为它会自动上转换) .

methodAdd.Invoke(dbSetItem, new object[] { entity });

【讨论】:

  • 我仍然收到错误,null ref。异常:“附加信息:对象引用未设置为对象的实例。”
  • @Luther:错过了那个问题,dbSetItemPropertyInfo,你需要打电话给PropertyType
【解决方案3】:

我觉得你的方法有点不对。

由于您已经在 DbContext 类中,我假设 this 是上下文。

var dbSet = this.Set<TypeEntity>();

                dbSet.Add(entity);

更新

你应该改变

dbsetItem.GetType().GetMethod("Add");

dbsetItem.PropertyType.GetMethod("Add");

typesToRegister.First() 返回一个PropertyInfo,所以我们不能使用GetType .. 而是使用PropertyType

你也需要这个改变。

更新 2

var dbSet = this.Set<TypeEntity>(); // an actual instance that can be passed to Invoke

    methodAdd.Invoke(dbSet, new TypeEntity[] { entity });

【讨论】:

  • 是的,我知道,但我想使用反射。这是我正在做的一个基本示例,但对于实际问题,我需要反思。
  • @Luther 我已经更新了我的答案。通过此更改,您不会得到空值。
  • 我已经按照你说的编辑了代码,但是在“methodAdd.Invoke(dbsetItem, new TypeEntity[] { entity });”行(我也使用了对象而不是 TypeEntry)我收到一个错误:“mscorlib.dll 中发生了‘System.Reflection.TargetException’类型的异常,但未在用户代码中处理附加信息:对象与目标类型不匹配。 "
  • @Luther 我想我现在明白了这个问题。 typesToRegister.First() 只是为您提供 Type 而不是它的实例。您需要将它的一个实例传递给 Invoke。我正在再次修改我的答案以包含此内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多