【问题标题】:Dynamic Entity EF5 Create And *REMOVE OR RECREATE* TypeBuilder动态实体 EF5 创建和*删除或重新创建* TypeBuilder
【发布时间】:2015-03-30 06:01:33
【问题描述】:

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

我的场景: 如果 DbContext 想要插入继承自 DynamicEntity 的静态实体(如 MyTableEntity),它将创建具有相同名称的具有“Dynamic_”前缀的实体(如 MyTableEntity)的动态类型,然后从生成的运行时类型创建实例,然后填充静态类型属性值 运行时对象的实例。最后插入方法将插入运行时对象。 每件事都很好并且工作。 但是因为 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();

【问题讨论】:

  • 为什么需要删除旧类型?你遇到了什么错误?
  • 当我想添加实体时,它会说:指定的架构无效。错误:CLR 类型到 EDM 类型的映射不明确,因为多个 CLR 类型与 EDM 类型“Dynamic_MyTableEntity”匹配。以前找到 CLR 类型“Dynamic_MyTableEntity”,新找到 CLR 类型“Dynamic_MyTableEntity”。

标签: c# entity-framework runtime il


【解决方案1】:

最后我改变了我的 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 工作正常...

【讨论】:

    猜你喜欢
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多