我必须使用带有动态表列的实体框架(用户可以将列添加到我的表中),我需要动态运行时类型实体来映射我的表。
我的场景:如果DbContext想插入继承自DynamicEntity的静态实体(如MyTableEntity),它将创建带有"Dynamic_“前缀的实体名称相同的动态类型(如MyTableEntity),然后从生成的运行时类型创建实例,然后将静态类型属性值填充到运行时对象的实例。最后,insert方法将插入运行时对象。每件事都是好的和工作的。但是,由于TypeBuilder创建运行时类型,如果我两次或更多次调用insert,TypeBuilder将创建新类型,名称类似于"Dynamic_MyTableEntity“,DbContext无法识别女巫类必须插入,这是很自然的。
我的问题:如何删除由TypeBuilder创建的旧类型,或者更新或更新旧类型,比如首先删除所有属性,然后再添加所有属性。
我创建从DynamicObject继承的类,并从DynamicEntity类继承动态实体。
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();发布于 2015-04-04 06:18:13
最后,我更改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工作得很好.
https://stackoverflow.com/questions/29339332
复制相似问题