2014-10-27 2 views
8

Что делать, если я хочу получить доступ к уникальной функции для РСУБД? Есть ли способ внедрить конкретный SQL-код SQL в SQL, созданный EF?Утечка абстракции Entity Framework - немного

Например, в Oracle 12c можно добавить временную валидность DDL и DML (есть большое разнообразие, я буду использовать только простые примеры здесь):

Это может быть хорошо смоделированы в C#:

[TemporalAxis("valid_time")] 
public class SomeEntity 
{ 
    public string SomeField { get; set; } 
} 

Затем используется с LINQ

var results = context.SomeEntities 
       .Where(i => i.SomeField = "some_value") 
       .AsOfPeriodFor("valid_time", dateVariable); 

.AsOfPeriodFor расширения может быть что-то вроде этого:

public static class TemporalExtensions 
{ 
    public static IEnumerable<TSource> AsOfPeriodFor<TSource>(this IEnumerable<TSource> source, 
     string temporalAxis, DateTime asOfDate) 
    { 
     // reflect on TSource to ensure it has the correct attribute/value (else degrade/throw) 
     // do something to source that sets up EF to add the extra clause in the DML 

     return source; 
    } 
} 

И я догадываюсь, что DbContext может отражать свои сущности, чтобы управлять DDL во время инициализации (мне нужно будет узнать больше об этом).

В результате вышеперечисленное EF испустит следующий SQL

DDL (при инициализации времени):

create table some_table 
    some_field varchar2(30) 

    period for valid_time -- Need to inject this at DB Initialize time 
); 

DML (во время запроса):

select 
    some_field 
from 
    some_table 
    as of period for valid_time to_timestamp('27-Oct-14') -- and this at query time 
where 
    some_field = 'some_value'; 

Мой вопрос : Доступны ли крючки или II-интерфейсы для ввода этих специальных фраз РСУБД в SQL, сгенерированный EF? Или вам придется выйти замуж за выше с помощью специального поставщика Oracle DB? Возможно ли это, и можете ли вы указать мне блог/книгу/видео/гуру, который может дать руководство?

+1

Является ли EF открытым исходным кодом? – Ben

+1

@Ben Хорошая мысль - я об этом не думал. Если все остальное не получится, я просмотрю код. Я надеялся, что будут общие шаблоны, лучшие практики, в которых кто-то может указать мне. – biscuit314

+0

Поскольку запрос - это просто IQueryable, и вы, похоже, знаете параметры во время компиляции, казалось бы, вы могли бы продолжать стекировать условные предикаты в исходном запросе, пока не будете готовы выполнить, правильно? В случае, если вам нужны манипуляции с данными при вставке, обновлении, удалении, вы можете добавить триггеры, которые поддерживаются EF, и в качестве последнего средства просто сопоставьте объект с хранимым proc. –

ответ

1

Невозможно, насколько мне известно, изменить SQL, который генерируется поставщиком EF.

Однако для этих особых случаев вы можете запускать SQL напрямую.

context.Database.SqlQuery<SomeEntity>("select * from SomeEntity " + 
"some more custom sql here " + 
"where somecomlumn = @p1", parameter1); 

Вам просто нужно убедиться, что все, что вы вернете, соответствует форме SomeEntity.

0

Реализовать Interceptor: EF-Tutorial

выглядит следующим образом:

class EFCommandInterceptor: IDbCommandInterceptor 
     { 
      public void NonQueryExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 
      { 
       LogInfo("NonQueryExecuted", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText)); 
      } 

      public void NonQueryExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 
      { 
       LogInfo("NonQueryExecuting", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText)); 
      } 

      public void ReaderExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContextt<System.Data.Common.DbDataReader> interceptionContext) 
      { 
       LogInfo("ReaderExecuted", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText)); 
      } 

      public void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext) 
      { 
       LogInfo("ReaderExecuting", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText)); 
      } 

      public void ScalarExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 
      { 
       LogInfo("ScalarExecuted", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText)); 
      } 

      public void ScalarExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 
      { 
       LogInfo("ScalarExecuting", String.Format(" IsAsync: {0}, Command Text: {1}", interceptionContext.IsAsync, command.CommandText)); 
      } 

      private void LogInfo(string command, string commandText) 
      { 
       Console.WriteLine("Intercepted on: {0} :- {1} ", command, commandText); 
      } 
     } 

Но как получить тип, чтобы получить метаданные я не знаю теперь.

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