如何将 DbSet<EntityName> 添加到使用 Codedom 动态生成的上下文中?

How to add DbSet<EntityName> to a context that is generated dynamically with Codedom?

我正在使用 Codedom 动态生成实体。我也没有硬编码上下文 class 作为解决方案的一部分。也就是说,我还在 运行 时间使用 Codedom 生成上下文。我这样做是为了让每个生成的实体都有自己的上下文。我 运行 遇到了为上下文 class 编写 Codedom 代码的问题。作为上下文的一部分,我需要在 DbSet 属性 中写入,以便生成的实体可以成为上下文模型的一部分。更具体地说,我在生成的上下文中需要以下行:

public DbSet<EntityName> EntityNames { get; set; }

其中 EntityName 是我创建的实体 class 类型的名称,而 EntityNames 就是那个末尾带有 's' 的名称。例如,我可能会创建一个 Employee 实体,所以我想生成一个上下文:

public DbSet<Employee> Employees { get; set; }

为此,我正在编写 returns 此 CodeMemberProperty 的方法。它知道写 Employee/Employees 因为我传入了实体的名称。没关系。到目前为止,该方法如下所示:

public static CodeMemberProperty HardCodeDbSet(string contextName)
{
    string entityName = contextName.Substring(0, contextName.Length - 7);
    CodeMemberProperty prop = new CodeMemberProperty();
    prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
    prop.Name = entityName + "s";
    prop.Type = new CodeTypeReference(typeof(DbSet<>));
    return prop;
}

这一行的原因:

string entityName = contextName.Substring(0, contextName.Length - 7);

是我将生成的上下文的名称设为相应的实体名称 + "Context",因此在该行中我将删除 "Context" 以取回实体名称。无论如何,这并不真正相关。给我带来麻烦的是类型一:

prop.Type = new CodeTypeReference(typeof(DbSet<>));

这只是给我:

DbSet<>

但我需要:

DbSet<EntityName>

如果我尝试在尖括号内写入任何内容,我会收到一条错误消息,指出它无法解析该符号。例如我想写:

prob.Type = new CodeTypeReference(typeof(DbSet<entityType>));

而且我可以

Type entityType

这个方法的一个参数,但它不喜欢那个。

有人知道解决这个问题的方法吗?我认为编写此代码会简单得多,但 Codedom 有时并不像我想象的那样合作...

如果我们深入到问题的核心,您在这里基本上要问的是如何使用反射来获取封闭泛型类型的类型。这与 CodeDom 或 EntityFramework 没有任何关系。

正如您提到的,使用 typeof(DbSet<>)(或 List<> 或任何东西)将为您提供 "open generic type",这意味着特定泛型类型所基于的类型。从这里,您可以使用方法 MakeGenericType 创建特定的封闭泛型类型:

var openType = typeof(DbSet<>);
var closedType = openType.MakeGenericType(entityType);

您需要采用开放式泛型 DbSet<> 并将其关闭,如下所示:

typeof(DbSet<>).MakeGenericType(entityType)