通用生成实体给出'实体类型不是当前上下文'重新编译模型的模型的一部分

问题描述 投票:0回答:3

我有一个问题,它完全停留在该做什么。我是EF新手:(

我使用了Adriaan Booysen的code创建了一个动态模型。由于局限性,我不能使用WCFDataService,而且我已经改变了一些代码以使其适用于我。当我第一次运行它时,它工作,我得到我的数据,但是当我再次执行该方法时,我得到的错误是实体类型不是模型的一部分。

我注意到的是,当我运行应用程序并创建第一个实体时,OnModelCreating被触发,并且模型被添加,但第二次没有发生,我认为这就是我得到错误的原因,但是我不知道该怎么办才能再次开火。

这是DynamicDbContext的代码

public partial class DynamicDbContext : DbContext
{
    public DynamicDbContext()
        : base("name=DynamicDbContext")
    {
        Database.SetInitializer(new NullDatabaseInitializer<DynamicDbContext>());
    }

    public void AddTable(Type type, List<string> KeyFields)
    {
        _tables.Add(type.Name, type);
        _keys = KeyFields;
    }

    private List<string> _keys;
    private Dictionary<string, Type> _tables = new Dictionary<string, Type>();

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //base.OnModelCreating(modelBuilder);
        var entityMethod = modelBuilder.GetType().GetMethod("Entity");

        foreach (var table in _tables)
        {
            entityMethod.MakeGenericMethod(table.Value).Invoke(modelBuilder, new object[] { });
            foreach (var pi in (table.Value).GetProperties())
            {
                if (_keys.Contains(pi.Name.ToUpper()))
                    modelBuilder.Entity(table.Value).HasKey(pi.PropertyType, pi.Name);
                else
                    switch (pi.PropertyType.Name)
                    {
                        case "Int16":
                        case "Int32":
                        case "Int64":
                        case "Boolean":
                            modelBuilder.Entity(table.Value).PrimitiveProperty(pi.PropertyType, pi.Name);
                            break;
                        default:
                            modelBuilder.Entity(table.Value).DynamicProperty(pi.PropertyType, pi.Name);
                            break;
                    }
            }
        }
    }
}

我有一个班级然后得到DbSet

public class Class1 : DynamicDbContext
{

    public DbSet LoadTypes(string TableName, Dictionary<string, Type> Fields, List<string> KeyFields)
    {
        var dcf = new DynamicClassFactory("Query." + TableName);
        var type = CreateType(dcf, TableName, Fields);

        AddTable(type, KeyFields);
        return Set(type);
    }

    private static Type CreateType(DynamicClassFactory dcf, string name, Dictionary<string, Type> Fields)
    {
        var type = dcf.CreateDynamicType<BaseDynamicEntity>(name, Fields);
        return type;
    }
}

DynamicClassFactory创建了内存组件。如果您查看代码项目代码,您可以看到它的作用。我没有改变任何东西。

在我的申请中,我执行以下操作:

var c = new Class1();
var Types = new Dictionary<string, Type>();
/*Code to populate the Fields and Field Types into the Types variable*/
source.QueryableSource = c.LoadTypes(TableName, Types, new List<string>() { "NO" });

source是来自DevExpress的EntityServerModeSource,允许我更有效地填充一个支点。如果有人能指出我正确的方向,我可以弄清楚,但目前我不知道该怎么办。

c# entity-framework dynamic dbcontext
3个回答
1
投票

嘿,我认为这很可能是由于即使您处置上下文,您将遇到一些问题与EF缓存模型构建器的东西

public class DwContext : DbContext, IDbModelCacheKeyProvider
{
    string IDbModelCacheKeyProvider.CacheKey => DwContextSettings.cacheKey;
    ...
}

0
投票

我通过使用编译模型来实现它。因为我没有创建数据库或在模型中进行任何更新,插入或删除,只是使用它来从一个或多个表中检索数据,我将代码从OnModelCreating移动到我的DbContext类中的静态方法,并调用它来自构造函数,它在打开查询时编译模型。这是代码

public DynamicDbContext(string connString, Type type, List<string> KeyFields)
    : base(GetConnection(connString), GenerateDbCompiledModel(connString, type, KeyFields), true)
{
    Database.SetInitializer(new NullDatabaseInitializer<DynamicDbContext>());
}

private static DbConnection GetConnection(string connectionString)
{
    var factory = DbProviderFactories.GetFactory("Oracle.ManagedDataAccess.Client");
    var conn = factory.CreateConnection();
    conn.ConnectionString = connectionString;
    return conn;
}

public static DbCompiledModel GenerateDbCompiledModel(string connectionString, Type entityType, List<string> _keys)
{
    string tableName = entityType.Name;
    string schema = entityType.FullName.Replace("Dynamic.Objects.", "").Replace("." + tableName, "");

    _keys = _keys.Select(x =>
    {
        x = x.ToUpper();
        return x;
    }).ToList();

    tableName = entityType.Name;
    DbModelBuilder dbModelBuilder = new DbModelBuilder(DbModelBuilderVersion.Latest);
    var entityMethod = dbModelBuilder.GetType().GetMethod("Entity");
    dbModelBuilder.HasDefaultSchema(schema);
    entityMethod.MakeGenericMethod(entityType).Invoke(dbModelBuilder, new object[] { });
    foreach (var pi in (entityType).GetProperties())
    {
        if (_keys.Contains(pi.Name.ToUpper()))
            dbModelBuilder.Entity(entityType).HasKey(pi.PropertyType, pi.Name);
        else
            switch (pi.PropertyType.Name)
            {
                case "Int16":
                case "Int32":
                case "Int64":
                case "Boolean":
                    dbModelBuilder.Entity(entityType).PrimitiveProperty(pi.PropertyType, pi.Name);
                    break;
                default:
                    dbModelBuilder.Entity(entityType).DynamicProperty(pi.PropertyType, pi.Name);
                    break;
            }
    }
    var factory = DbProviderFactories.GetFactory("Oracle.ManagedDataAccess.Client"); // Oracle.ManagedDataAccess.Client");
    var conn = factory.CreateConnection();
    conn.ConnectionString = connectionString;

    return dbModelBuilder.Build(conn).Compile();
}

我有GetConnection的原因是因为应用程序也使用Devart,并且由于某种原因,new OracleConnection使用了其中一个,这给了我另一个错误消息。

我的实体包含了Schema和Table Name作为全名的一部分,这就是为什么我可以从qazxsw poi中提取模式的原因

我希望这有助于那些想要动态创建实体模型以供显示的人。


-1
投票

当您的连接字符串不正确时,问题通常会发生。检查提供商名称和可能的EF内容

© www.soinside.com 2019 - 2024. All rights reserved.