动态实体 EF5 创建并*删除或重新创建* TypeBuilder
Dynamic Entity EF5 Create And *REMOVE OR RECREATE* TypeBuilder
我必须将 entity framework 与动态 table 列一起使用(该用户可以将列添加到我的 table),并且我需要动态 运行-时间键入实体以映射我的 table.
我的场景:
如果 DbContext 想要插入从 DynamicEntity 继承的静态实体(如 MyTableEntity),它将创建具有相同名称的实体(如 MyTableEntity)的动态类型,前缀为 "Dynamic_",然后从生成的 运行time 创建实例类型,然后将静态类型属性值填充到
运行时间对象的实例。最后插入方法将插入 运行time 对象。
一切都很好,工作。
但是因为 TypeBuilder 创建 运行time 类型并且如果我调用插入两次或更多次,TypeBuilder 将创建具有相同名称的新类型,如 "Dynamic_MyTableEntity" 并且 DbContext 无法识别 class 必须插入自然。
我的问题:
我如何删除由 TypeBuilder 创建的旧类型或更新或更新旧类型,例如首先删除所有属性然后再次添加所有属性。
我创建了从 DynamicObject 继承的 class,我将从 DynamicEntity class.
继承我的动态实体
public class DynamicEntity : System.Dynamic.DynamicObject {
//Runtime Type Prefix
public const string DynamicTypePrefix = "Dynamic_";
//Dictionary Key = PropertyName, Value = Value Of Property
private Dictionary<string, object> properties = new Dictionary<string, object>();
//Dictionary Key = typeof static type, Value = Dynamic Type, Corresponding static type
private static Dictionary<Type, Type> staticType_DynamicType = new Dictionary<Type, Type>();
private static Assembly currentAssembly;
private Assembly CurrentAssembly {
get {
if (currentAssembly == null) {
currentAssembly = Assembly.GetAssembly(type);
}
return currentAssembly;
}
}
//Generate dynamic type from static type, and Cache it to staticType_DynamicType for later use, and return
public Type GetDynamicType() {
Type dynamicType;
if (!staticType_DynamicType.TryGetValue(type, out dynamicType)) {
TypeBuilder typeBuilder = CreateTypeBuilder(CurrentAssembly.FullName, CurrentAssembly.GetLoadedModules()[0].Name, DynamicTypePrefix + type.Name);
foreach (var item in properties.Where(q => q.Value != null).Select(q => new { Name = q.Key, Type = q.Value.GetType() })) {
CreateAutoImplementedProperty(typeBuilder, item.Name, item.Type);
}
dynamicType = typeBuilder.CreateType();
staticType_DynamicType[type] = dynamicType;
}
return dynamicType;
}
//Create TypeBuilder
private TypeBuilder CreateTypeBuilder(string assemblyName, string moduleName, string typeName) {
TypeBuilder typeBuilder = AppDomain
.CurrentDomain
.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run)
.DefineDynamicModule(moduleName)
.DefineType(typeName, TypeAttributes.Public, type);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
return typeBuilder;
}
//Create Property for TypeBuilder
private static void CreateAutoImplementedProperty(
TypeBuilder builder, string propertyName, Type propertyType) {
const string PrivateFieldPrefix = "m_";
const string GetterPrefix = "get_";
const string SetterPrefix = "set_";
// Generate the field.
FieldBuilder fieldBuilder = builder.DefineField(
string.Concat(PrivateFieldPrefix, propertyName),
propertyType, FieldAttributes.Private);
// Generate the property
PropertyBuilder propertyBuilder = builder.DefineProperty(
propertyName, System.Reflection.PropertyAttributes.HasDefault, propertyType, null);
// Property getter and setter attributes.
MethodAttributes propertyMethodAttributes =
MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig;
// Define the getter method.
MethodBuilder getterMethod = builder.DefineMethod(
string.Concat(GetterPrefix, propertyName),
propertyMethodAttributes, propertyType, Type.EmptyTypes);
// Emit the IL code.
// ldarg.0
// ldfld,_field
// ret
ILGenerator getterILCode = getterMethod.GetILGenerator();
getterILCode.Emit(OpCodes.Ldarg_0);
getterILCode.Emit(OpCodes.Ldfld, fieldBuilder);
getterILCode.Emit(OpCodes.Ret);
// Define the setter method.
MethodBuilder setterMethod = builder.DefineMethod(
string.Concat(SetterPrefix, propertyName),
propertyMethodAttributes, null, new Type[] { propertyType });
// Emit the IL code.
// ldarg.0
// ldarg.1
// stfld,_field
// ret
ILGenerator setterILCode = setterMethod.GetILGenerator();
setterILCode.Emit(OpCodes.Ldarg_0);
setterILCode.Emit(OpCodes.Ldarg_1);
setterILCode.Emit(OpCodes.Stfld, fieldBuilder);
setterILCode.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getterMethod);
propertyBuilder.SetSetMethod(setterMethod);
}
//Create new instance from runtime type and initialize properties with static type
public object CreateDynamicInstance() {
Type dynamicType = GetDynamicType();
object instance = Activator.CreateInstance(dynamicType);
foreach (var item in type.GetProperties()) {
dynamicType.GetProperty(item.Name).SetValue(instance, item.GetValue(this, null), null);
}
foreach (var item in properties) {
dynamicType.GetProperty(item.Key).SetValue(instance, item.Value, null);
}
return instance;
}
//Static type
private Type type;
public DynamicEntity() {
type = this.GetType();
}
//Set Dynamic Property to static type
public void SetMember(string name, object value) {
lock (this) {
properties[name] = value;
if (staticType_DynamicType.ContainsKey(type)) {
staticType_DynamicType.Remove(type);
}
}
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
SetMember(binder.Name, value);
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
lock (this) {
result = properties[binder.Name];
}
return true;
}
}
对我的实体进行采样:
public class MyTableEntity : DynamicEntity {
[Key]
public int ID { get; set; }
}
示例使用:
dynamic entity = new MyTableEntity();
entity.SetMember("MyNewColumn", "this is value of column"); //or entity.MyNewColumn = "this is value of column";
myDbContext.Set(entity.GetDynamicType()).Add(entity.CreateDynamicInstance());
myDbContext.SaveChanges();
最后我更改了我的 dbcontext,我的问题解决了
public class HREntities : DbContext {
public HREntities(string connectionString)
: base(connectionString) {
}
public HREntities(string connectionString, Type entityType)
: base(connectionString, GenerateDbCompiledModel(connectionString, entityType)) {
}
private static DbCompiledModel GenerateDbCompiledModel(string connectionString, Type entityType) {
string tableName;
if (typeof(DynamicEntity).IsAssignableFrom(entityType)) {
tableName = entityType.Name.Substring((DynamicEntity.DynamicTypePrefix + "tbl").Length);
}
else {
tableName = entityType.Name.Substring("tbl".Length);
}
DbModelBuilder dbModelBuilder = new DbModelBuilder(DbModelBuilderVersion.Latest);
var entityMethod = dbModelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(entityType);
var entityTypeConfiguration = entityMethod.Invoke(dbModelBuilder, new object[0]);
entityTypeConfiguration.GetType().GetMethod("ToTable", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null).Invoke(entityTypeConfiguration, new object[] { tableName });
return dbModelBuilder.Build(new SqlConnection(connectionString)).Compile();
}
}
每次当我想创建 HREntities 实例时,我都会传递我的动态类型并且我的 dbcontext 工作正常...
我必须将 entity framework 与动态 table 列一起使用(该用户可以将列添加到我的 table),并且我需要动态 运行-时间键入实体以映射我的 table.
我的场景: 如果 DbContext 想要插入从 DynamicEntity 继承的静态实体(如 MyTableEntity),它将创建具有相同名称的实体(如 MyTableEntity)的动态类型,前缀为 "Dynamic_",然后从生成的 运行time 创建实例类型,然后将静态类型属性值填充到 运行时间对象的实例。最后插入方法将插入 运行time 对象。 一切都很好,工作。 但是因为 TypeBuilder 创建 运行time 类型并且如果我调用插入两次或更多次,TypeBuilder 将创建具有相同名称的新类型,如 "Dynamic_MyTableEntity" 并且 DbContext 无法识别 class 必须插入自然。
我的问题: 我如何删除由 TypeBuilder 创建的旧类型或更新或更新旧类型,例如首先删除所有属性然后再次添加所有属性。
我创建了从 DynamicObject 继承的 class,我将从 DynamicEntity class.
继承我的动态实体public class DynamicEntity : System.Dynamic.DynamicObject {
//Runtime Type Prefix
public const string DynamicTypePrefix = "Dynamic_";
//Dictionary Key = PropertyName, Value = Value Of Property
private Dictionary<string, object> properties = new Dictionary<string, object>();
//Dictionary Key = typeof static type, Value = Dynamic Type, Corresponding static type
private static Dictionary<Type, Type> staticType_DynamicType = new Dictionary<Type, Type>();
private static Assembly currentAssembly;
private Assembly CurrentAssembly {
get {
if (currentAssembly == null) {
currentAssembly = Assembly.GetAssembly(type);
}
return currentAssembly;
}
}
//Generate dynamic type from static type, and Cache it to staticType_DynamicType for later use, and return
public Type GetDynamicType() {
Type dynamicType;
if (!staticType_DynamicType.TryGetValue(type, out dynamicType)) {
TypeBuilder typeBuilder = CreateTypeBuilder(CurrentAssembly.FullName, CurrentAssembly.GetLoadedModules()[0].Name, DynamicTypePrefix + type.Name);
foreach (var item in properties.Where(q => q.Value != null).Select(q => new { Name = q.Key, Type = q.Value.GetType() })) {
CreateAutoImplementedProperty(typeBuilder, item.Name, item.Type);
}
dynamicType = typeBuilder.CreateType();
staticType_DynamicType[type] = dynamicType;
}
return dynamicType;
}
//Create TypeBuilder
private TypeBuilder CreateTypeBuilder(string assemblyName, string moduleName, string typeName) {
TypeBuilder typeBuilder = AppDomain
.CurrentDomain
.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run)
.DefineDynamicModule(moduleName)
.DefineType(typeName, TypeAttributes.Public, type);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
return typeBuilder;
}
//Create Property for TypeBuilder
private static void CreateAutoImplementedProperty(
TypeBuilder builder, string propertyName, Type propertyType) {
const string PrivateFieldPrefix = "m_";
const string GetterPrefix = "get_";
const string SetterPrefix = "set_";
// Generate the field.
FieldBuilder fieldBuilder = builder.DefineField(
string.Concat(PrivateFieldPrefix, propertyName),
propertyType, FieldAttributes.Private);
// Generate the property
PropertyBuilder propertyBuilder = builder.DefineProperty(
propertyName, System.Reflection.PropertyAttributes.HasDefault, propertyType, null);
// Property getter and setter attributes.
MethodAttributes propertyMethodAttributes =
MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig;
// Define the getter method.
MethodBuilder getterMethod = builder.DefineMethod(
string.Concat(GetterPrefix, propertyName),
propertyMethodAttributes, propertyType, Type.EmptyTypes);
// Emit the IL code.
// ldarg.0
// ldfld,_field
// ret
ILGenerator getterILCode = getterMethod.GetILGenerator();
getterILCode.Emit(OpCodes.Ldarg_0);
getterILCode.Emit(OpCodes.Ldfld, fieldBuilder);
getterILCode.Emit(OpCodes.Ret);
// Define the setter method.
MethodBuilder setterMethod = builder.DefineMethod(
string.Concat(SetterPrefix, propertyName),
propertyMethodAttributes, null, new Type[] { propertyType });
// Emit the IL code.
// ldarg.0
// ldarg.1
// stfld,_field
// ret
ILGenerator setterILCode = setterMethod.GetILGenerator();
setterILCode.Emit(OpCodes.Ldarg_0);
setterILCode.Emit(OpCodes.Ldarg_1);
setterILCode.Emit(OpCodes.Stfld, fieldBuilder);
setterILCode.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getterMethod);
propertyBuilder.SetSetMethod(setterMethod);
}
//Create new instance from runtime type and initialize properties with static type
public object CreateDynamicInstance() {
Type dynamicType = GetDynamicType();
object instance = Activator.CreateInstance(dynamicType);
foreach (var item in type.GetProperties()) {
dynamicType.GetProperty(item.Name).SetValue(instance, item.GetValue(this, null), null);
}
foreach (var item in properties) {
dynamicType.GetProperty(item.Key).SetValue(instance, item.Value, null);
}
return instance;
}
//Static type
private Type type;
public DynamicEntity() {
type = this.GetType();
}
//Set Dynamic Property to static type
public void SetMember(string name, object value) {
lock (this) {
properties[name] = value;
if (staticType_DynamicType.ContainsKey(type)) {
staticType_DynamicType.Remove(type);
}
}
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
SetMember(binder.Name, value);
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
lock (this) {
result = properties[binder.Name];
}
return true;
}
}
对我的实体进行采样:
public class MyTableEntity : DynamicEntity {
[Key]
public int ID { get; set; }
}
示例使用:
dynamic entity = new MyTableEntity();
entity.SetMember("MyNewColumn", "this is value of column"); //or entity.MyNewColumn = "this is value of column";
myDbContext.Set(entity.GetDynamicType()).Add(entity.CreateDynamicInstance());
myDbContext.SaveChanges();
最后我更改了我的 dbcontext,我的问题解决了
public class HREntities : DbContext {
public HREntities(string connectionString)
: base(connectionString) {
}
public HREntities(string connectionString, Type entityType)
: base(connectionString, GenerateDbCompiledModel(connectionString, entityType)) {
}
private static DbCompiledModel GenerateDbCompiledModel(string connectionString, Type entityType) {
string tableName;
if (typeof(DynamicEntity).IsAssignableFrom(entityType)) {
tableName = entityType.Name.Substring((DynamicEntity.DynamicTypePrefix + "tbl").Length);
}
else {
tableName = entityType.Name.Substring("tbl".Length);
}
DbModelBuilder dbModelBuilder = new DbModelBuilder(DbModelBuilderVersion.Latest);
var entityMethod = dbModelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(entityType);
var entityTypeConfiguration = entityMethod.Invoke(dbModelBuilder, new object[0]);
entityTypeConfiguration.GetType().GetMethod("ToTable", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null).Invoke(entityTypeConfiguration, new object[] { tableName });
return dbModelBuilder.Build(new SqlConnection(connectionString)).Compile();
}
}
每次当我想创建 HREntities 实例时,我都会传递我的动态类型并且我的 dbcontext 工作正常...