通用生成的实体给出 'The entity type is not part of the model for the current context' 重新编译模型

generic generated entity gives 'The entity type is not part of the model for the current context' Recompile Model

我有一个问题,完全不知道该怎么做。我是 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;
                    }
            }
        }
    }
}

我有一个 class 然后得到 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 创建内存程序集。如果您查看 codeproject 代码,您可以看到它的作用。我在那里没有改变任何东西。

在我的应用程序中,我执行以下操作:

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,它允许我更有效地填充数据透视表。如果有人能给我指明正确的方向,我可以弄清楚,但目前我不确定该怎么做。

我通过使用编译模型让它工作。因为我没有创建数据库或在模型中进行任何更新、插入或删除,而只是使用它从 table 或 table 中检索数据,所以我将代码从 OnModelCreating 移到了我的 DbContext class 中的静态方法,并从构造函数调用它,它在我打开查询时编译模型。这是代码

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 使用了其中一个,这给了我另一个错误消息。

我的实体包括模式和表名作为全名的一部分,这就是为什么我可以从 entityType.FullName

中提取模式的原因

我希望这对那些也想为显示目的动态创建实体模型的人有所帮助。

问题大多发生在您的连接字符串不正确时。检查提供者名称和可能的 EF 内容

嘿,我认为这很可能是因为即使你处理上下文,你也会遇到一些 EF 缓存模型构建器内容的问题

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