2014-12-02 3 views
3

Предположим, что у меня есть таблица db с именем Сотрудник и соответствующая модель EF 6.0 db-first.Изменить имя таблицы во время выполнения

Получение всех строк таблицы сотрудников осуществляются с помощью запроса: context.Employees.ToList()

Можно, во время выполнения и по требованию, чтобы перенаправить имя таблицы БД в Test1 при использовании же имени объекта и запроса ?

Может быть, случай использования EF 6.0 Interceptor?

+0

кажется очень странным требованием; можете ли вы подробнее объяснить, что вы пытаетесь выполнить, изменив имя таблицы? – Claies

+0

История моего req такова: таблица db хранит много миллионов записей. Чтобы гарантировать приемлемую повседневную производительность, я хочу провести «последние» записи в основной таблице (около 1-2 миллионов) и переместить по расписанию все «старые» записи (> 100 миллионов в общей сложности) во вторичную идентичную таблицу. Пользователь может с помощью переключателя уровня приложения использовать режим «исторические данные» и переключиться на вторичную таблицу, используя точно такую ​​же модель, объекты и запросы – GrMikeD

+0

Я не уверен, возможно ли это с помощью первой модели БД, но я знаю это возможно с использованием кода First. Вы можете узнать больше о моих промах в моем ответе на аналогичный вопрос (используя Code First) [здесь] (http://stackoverflow.com/questions/27032292/entity-framework-code-first-returning-same-data-for -Разные столы, отображенные к s/27050034 # 27050034). –

ответ

-1

Почему бы не использовать какой-то хороший старомодный полиморфизм?

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()); 
0

Я не знаю, если вы должны сделать это, но я думаю, что вы можете . Вам придется искать в структурах метаданных Entity Framework, таких как MetadataWorkspace, которые вы можете получить из базового объекта ObjectContext. См. Пример: http://weblogs.asp.net/ricardoperes/entity-framework-metadata.

+0

Для чего вы можете получить метаданные, как вы описали, но вы не можете изменить отображение таблицы по этому маршруту (я уже пробовал). Несмотря на то, что свойство является свойством чтения и записи, существует внутренний механизм, который идентифицирует его как доступный только для чтения и выдает исключение, когда вы пытаетесь его изменить. –

+0

Да, я так и думал ... спасибо! –

0

Спасибо за ответы.

Я думаю, что мой случай - это сценарий реального мира, который, как правило, игнорируется во всех типичных сценариях учебников и примеров EF «с запуском».

Основываясь на том, что я использую подход db-first, и коммутатор должен находиться на уровне приложения, я думаю, что создам экземпляр Context на основе другого SSDL с новым именем таблицы, которое пользователь будет использовать на требовать

0

Я хотел бы сделать что-то вроде этого:

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() запускается один раз. Поэтому, если вы используете его в том же приложении, это займет первое имя таблицы, так как оно кэширует результат.

3

Я знаю, что прошло с момента публикации, но я добавлю свой ответ, чтобы помочь кому-то другому. У меня были общие таблицы очереди 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); 
    } 
} 

Конечно, вам нужно получить новое имя таблицы откуда-то. Либо из конструктора, либо из сохраненного поля в вашем настраиваемом DBC-тексте, который вы можете захватить из 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 QueueMessageInterceptor()); 
    } 
} 

UPDATE: Я обнаружил, что если добавить перехватчик в конструкторе выше вызвать утечку памяти. 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; 
    } 
} 
0

Старый вопрос, но на основе проблемы, я хотел бы предложить, что вы смотрите на partioning таблицы на основе «текущий» бит или поле даты и времени. Разделение основано на значении столбца & поддерживается самой современной СУБД. Это позволило бы избежать проблем на уровне ORM.

Смежные вопросы