【问题标题】:Is there a way to call generic repository methods on an entity that was generated at run time with codeDOM?有没有办法在运行时使用 codeDOM 生成的实体上调用通用存储库方法?
【发布时间】:2015-06-18 23:05:04
【问题描述】:

我正在使用 codeDOM 在运行时生成我的实体类。我还有一个通用存储库来处理各种数据库功能。这是我的通用存储库中作为示例方法的 Insert 方法:

public void Insert<TEntity>(TEntity entity) where TEntity : class, IBusinessEntity
{
    if (entity == null)
    {
        throw new ArgumentNullException("entity");
    }

    TEntity existing = Existing(entity);
    if (existing == null)
    {
        _context.Set<TEntity>().Add(entity);
        this._context.SaveChanges();
    }
}

以下是一些示例代码,说明了我如何生成实体类以及如何使用 codeDOM 基于该实体类创建实体:

//Generate the fields of the new entity class
EntityGenerator.EntityFieldInfo entityField1 = new EntityGenerator.EntityFieldInfo("Name", typeof(string), RelationshipType.NoRelation);
EntityGenerator.EntityFieldInfo entityField2 = new EntityGenerator.EntityFieldInfo("Shape", typeof(string), RelationshipType.NoRelation);
ICollection<EntityGenerator.EntityFieldInfo> entityFieldList = new List<EntityGenerator.EntityFieldInfo> { entityField1, entityField2 };

// Create the new entity class using the fields established above 
// as well as the name of the entity (typeName = "Thing")
string typeName = "Thing";
EntityGenerator.CreateEntityClass(entityFieldList, typeName);
CompilerResults results = EntityGenerator.GetCompiledEntity(typeName);

// Create an entity instance based on the new entity class that was just created
Object newThing = EntityGenerator.CreateInstanceOfEntity(results, typeName);
SetObjectField(newEntity, "Name", "Box");
SetObjectField(newEntity, "Shape", "Cuboid");

如您所见,newThing(新实体实例)是一个 Object 类型。如果这是一个硬编码的实体类,那么我可以说

Thing newThing;

但 CodeDOM 创建的 Thing 实体不是硬编码类,因此我必须使用 Object 类型而不是 Thing 类型。这是一个问题,因为我使用的是通用存储库。假设我想将此实体插入数据库。我想打电话:

myRepository.Insert<Thing>(newThing);

但是,Thing 只是由 CodeDOM 在运行时创建的,所以它不是一个类,这意味着它不能进入​​ 。您可能已经注意到上面我的 Insert 方法中,TEntity 也是一个 IBusinessEntity。如果我尝试

myRepository.Insert<IBusinessEntity>(newThing);

我得到错误:

参数类型“object”不可分配给参数类型“Models.IBusinessEntity”

如果我尝试在 中不添加任何内容,如下所示:

myRepository.Insert(newThing);

我得到错误:

“object”类型必须可转换为“Models.IBusinessEntity”,才能在通用方法“void Insert(TEntity)”中用作参数“TEntity”。

有谁知道如何协调这个 codeDOM 生成的实体与通用存储库?反思有帮助吗?如果反射能以某种方式给我一个可以传递到 的事物类,那就太好了。另外我应该注意,我使用 CodeDOM 创建的所有实体都扩展了 IBusinessEntity。

【问题讨论】:

  • 你生成的类型是否实现了接口?即使是这样,我也不认为您可以拥有 'DbSet',因为 EF 在实体化实体时不知道要实例化哪个对象。如果模型必须匹配数据库,我也不清楚为什么要动态生成类型......
  • 我必须动态生成类型,因为我们允许用户创建自己的实体。所以我们从 sql 表中提取关于用户希望他们的实体看起来如何的数据,然后我们使用 codeDOM 创建它。而且我不知道如何将这个对象存储在数据库中。

标签: c# entity-framework generics reflection codedom


【解决方案1】:

我认为它很难工作,因为 EF 使用 DbContext 中包含的 DbSet 来创建映射。您认为如何创建它们?

无论如何,你不需要类型来使用 EF,你可以经常使用 GetType。 在您的方法中(缺少 Existing(.) 但我认为类似)您可以使用

public void Insert(object entity)
{
    if (entity == null)
        throw new ArgumentNullException("entity");

    if (!(entity is IBusinessEntity))
        throw new ArgumentInvalidException("entity is not an IBusinessEntity");

    object existing = Existing(entity);
    if (existing == null)
    {
        _context.Set(entity.GetType()).Add(entity);
        this._context.SaveChanges();
    }

}

使用 Set 或 Set(.) 我很确定 EF 会在从 DbContext 中包含的 DbSet 开始创建的映射中进行搜索。我不记得确切的例外,但我播种的时间不同(当我使用 DbContext.Set(myEntityType) 时)。

【讨论】:

  • 是的,我认为你是对的。我想我不能使用通用存储库,因此我必须在我的上下文类中对所有 DbSet 进行硬编码。然后在我的方法中,我可以检查实体的类型。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-18
  • 1970-01-01
  • 1970-01-01
  • 2021-08-03
  • 2017-01-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多