如何将 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)
我正在使用 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)