在运行时更改表名

GrM*_*keD 6 entity-framework entity-framework-6

假设我有一个名为Employee的 db 表和一个相应的 EF 6.0 db-first 模型。

获取表Employee 的所有行是通过查询完成的:context.Employees.ToList()

是否可以在运行时和按需将数据库表名称重定向到Test1,同时使用相同的对象名称和查询?

也许是 EF 6.0 拦截器使用的案例?

Eri*_*hun 7

我知道距离原始帖子已经有一段时间了,但我会添加我的答案以帮助其他人。我有具有不同表名的通用 SQL 队列表。即两个表的模式完全相同。我创建了一个框架,以便您可以通过提供名称来动态轮询您选择的表,这就是我需要在运行时更新表名称的原因。基本上,您可以创建一个拦截器来拦截来自实体框架的原始 SQL 查询并从那里更新表名。

public class MyInterceptor : IDbCommandInterceptor
{
    private const string TableReplaceString = "[TheTableNameToReplace]";

    private void ReplaceTableName(DbCommand command, IEnumerable<DbContext> contexts)
    {
        var myContext = contexts?.FirstOrDefault(x => x is MyContext) as MyContext;
        if (myContext != null && command != null && command.CommandText.Contains(TableReplaceString))
        {
            command.CommandText = command.CommandText.Replace(TableReplaceString, $"[{myContext.NewTableName}]");
        }
    }

    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        ReplaceTableName(command, interceptionContext.DbContexts);
    }

    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        ReplaceTableName(command, interceptionContext.DbContexts);
    }

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        ReplaceTableName(command, interceptionContext.DbContexts);
    }

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        ReplaceTableName(command, interceptionContext.DbContexts);
    }

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        ReplaceTableName(command, interceptionContext.DbContexts);
    }

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        ReplaceTableName(command, interceptionContext.DbContexts);
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,您必须从某个地方获取新表名。从构造函数或自定义 DBContext 中存储的字段,您可以从interceptionContext.DbContexts 中获取。

然后你只需要为你的上下文注册拦截器。

public class MyContext : DBContext
{
    public readonly string NewTableName;

    public MyContext(string connectionString, string newTableName)
        : base(connectionString)
    {
        NewTableName = newTableName;
        // Set interceptor
        DbInterception.Add(new MyInterceptor());
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:我发现如果在上面的构造函数中添加拦截器会导致内存泄漏。DotMemory 不会告诉你这个。确保在静态构造函数中添加拦截器。

public class MyContext : DBContext
{
    public readonly string NewTableName;

    static MyContext()
    {
        // Set interceptor only in static constructor
        DbInterception.Add(new MyInterceptor());
    }

    public MyContext(string connectionString, string newTableName)
        : base(connectionString)
    {
        NewTableName = newTableName;
    }
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*end -2

为什么不使用一些好的老式多态性呢?

partial class Employee : IEmployee { }
partial class HistoricalEmployee : IEmployee { }

interface IEmployee {
    public string Name { get; set; }
}

void PrintEmployeeName(IEmployee employee)
{
    Debug.WriteLine(employee.Name);
}

PrintEmployeeName(context.Employees.First());
PrintEmployeeName(context.HistoricalEmployees.First());
Run Code Online (Sandbox Code Playgroud)