让我们假设我有一个名为的员工和相应的EF 6.0 db-first模型的db表。在运行时更改表名
获取表的所有行员工通过查询完成:context.Employees.ToList()
是否有可能在运行时和需求,而使用相同的对象名称和查询到数据库表名重定向到的Test1 ?
EF 6.0 Interceptor的使用情况可能是这样吗?
让我们假设我有一个名为的员工和相应的EF 6.0 db-first模型的db表。在运行时更改表名
获取表的所有行员工通过查询完成:context.Employees.ToList()
是否有可能在运行时和需求,而使用相同的对象名称和查询到数据库表名重定向到的Test1 ?
EF 6.0 Interceptor的使用情况可能是这样吗?
为什么不使用一些很好的老式多态?
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());
我不知道你是否应该做到这一点,但我认为你可以。您将不得不深入实体框架元数据结构,例如MetadataWorkspace,您可以从底层ObjectContext获取该结构。在这里看到一个例子:http://weblogs.asp.net/ricardoperes/entity-framework-metadata。
对于它的价值,你可以按照你所描述的获取元数据,但是你不能通过这条路线改变表格映射(我已经尝试过)。尽管该属性是一个读写属性,但有一种内部机制将其标识为只读,并在尝试更改时引发异常。 – 2014-12-03 13:53:55
是的,我以为是...谢谢! – 2014-12-03 14:32:26
感谢您的答案。
我认为我的情况是一个真实世界的情景,在EF教程和示例的所有“入门”典型场景中通常都会被忽略。
基于我使用db-first方法并且应该在应用程序级别的事实,我认为我将创建一个Context实例,它基于不同的SSDL以及用户将使用的新表名要求
我会做这样的事情:
public partial class MyContext : DbContext
{
private readonly ITableNameProvider _tableNameProvider;
public MyContext(ITableNameProvider tableNameProvider)
: base("name=ConnectionStringName")
{
_tableNameProvider = tableNameProvider;
}
public virtual DbSet<MyGenericEntity> Templates { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyGenericEntity>()
.ToTable(_tableNameProvider.GetTableName(), _tableNameProvider.GetSchemaName());
}
}
,我认为它在您的方案。唯一的问题是OnModelCreating()只运行一次。因此,如果您在同一个应用程序中使用它,它将缓存结果后将第一个表名称。
我知道这已经有一段时间以来,原来的帖子,但我会加我的答案来帮助别人。我有具有不同表名的通用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);
}
}
当然,你必须从某个地方得到新的表名。无论是从构造函数还是从您可以从interceptionContext.DbContexts中获取的自定义DBContext中的存储字段。
然后你只需要为你的上下文注册拦截器。
public class MyContext : DBContext
{
public readonly string NewTableName;
public MyContext(string connectionString, string newTableName)
: base(connectionString)
{
NewTableName = newTableName;
// Set interceptor
DbInterception.Add(new QueueMessageInterceptor());
}
}
更新: 我发现,如果你在构造函数中添加拦截器上面会导致内存泄漏。 DotMemory不会告诉你这个问题。确保在静态构造函数中添加拦截器。
public class MyContext : DBContext
{
public readonly string NewTableName;
static MyContext()
{
// Set interceptor only in static constructor
DbInterception.Add(new QueueMessageInterceptor());
}
public MyContext(string connectionString, string newTableName)
: base(connectionString)
{
NewTableName = newTableName;
}
}
老问题,但基于这个问题我建议你看一下基于“当前”位或时间字段partioning你的表。分区基于列值&由大多数现代DBMS支持。它会避免ORM级别的问题。
似乎是一个非常奇怪的要求;你能否通过更改表名来解释更多关于你想要完成的事情? – Claies 2014-12-02 22:12:37
我的req背后的故事如下:db表存储了数百万条记录。为了保证可接受的日常表现,我想在主表中保留“最近”的记录(大约1-2百万),并将所有“旧”记录(总共> 1亿)记录到次要相同表格中。用户可以通过应用程序级别的开关使用“历史数据”模式并使用完全相同的模型,对象和查询切换到辅助表格 – GrMikeD 2014-12-02 22:20:58
我不确定这是否可以使用DB First模型,但我知道有可能使用Code First。你可以在我对类似问题的回答(使用Code First)中阅读更多我的ramblings [这里](http://stackoverflow.com/questions/27032292/entity-framework-code-first-returning-same-data-for - 不同-表映射到S/27050034#27050034)。 – 2014-12-02 22:28:47