首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >动态实体EF5创建和*删除或重新创建* TypeBuilder

动态实体EF5创建和*删除或重新创建* TypeBuilder
EN

Stack Overflow用户
提问于 2015-03-30 06:01:33
回答 1查看 585关注 0票数 1

我必须使用带有动态表列的实体框架(用户可以将列添加到我的表中),我需要动态运行时类型实体来映射我的表。

我的场景:如果DbContext想插入继承自DynamicEntity的静态实体(如MyTableEntity),它将创建带有"Dynamic_“前缀的实体名称相同的动态类型(如MyTableEntity),然后从生成的运行时类型创建实例,然后将静态类型属性值填充到运行时对象的实例。最后,insert方法将插入运行时对象。每件事都是好的和工作的。但是,由于TypeBuilder创建运行时类型,如果我两次或更多次调用insert,TypeBuilder将创建新类型,名称类似于"Dynamic_MyTableEntity“,DbContext无法识别女巫类必须插入,这是很自然的。

我的问题:如何删除由TypeBuilder创建的旧类型,或者更新或更新旧类型,比如首先删除所有属性,然后再添加所有属性。

我创建从DynamicObject继承的类,并从DynamicEntity类继承动态实体。

代码语言:javascript
复制
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;
    }
}

对我的实体进行抽样:

代码语言:javascript
复制
public class MyTableEntity : DynamicEntity {
    [Key]
    public int ID { get; set; }
}

样本使用:

代码语言:javascript
复制
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();
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-04-04 06:18:13

最后,我更改dbcontext并解决了我的问题。

代码语言:javascript
复制
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工作得很好.

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29339332

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档