2014-10-27 41 views
8

Co jeśli chcę uzyskać dostęp do funkcji unikatowej dla RDBMS? Czy istnieje sposób na wstrzyknięcie określonego SQL do SQL wygenerowanego przez EF?Pobranie abstrakcji Entity Framework - tylko trochę

Na przykład w Oracle 12c można dodać ważność czasową do DDL i DML (istnieje wiele odmian, użyję tylko proste przykłady tutaj):

Można to ładnie wymodelowanych w C#:

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

następnie wykorzystywane z LINQ

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

przedłużenie .AsOfPeriodFor może być coś takiego:

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; 
    } 
} 

I domyślam się, że DbContext może zastanowić się nad swoimi obiektami, aby sterować DDL w czasie inicjalizacji (będę musiał dowiedzieć się więcej na ten temat).

Rezultatem powyższego jest EF emituje następujące SQL

DLL (w initialize czas):

create table some_table 
    some_field varchar2(30) 

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

DML (w czasie wyszukiwania):

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'; 

My pytanie : Czy są dostępne hooki lub IInterfaces do wstrzykiwania tych zwrotów specjalistycznych RDBMS do SQL generowanego przez EF? Czy będziesz musiał się z tym ożenić z niestandardowym dostawcą Oracle DB? Czy to jest możliwe i czy możesz wskazać mi blog/książkę/wideo/guru, który może dostarczyć wskazówek?

+1

Czy EF nie jest open source? – Ben

+1

@Ben Dobra rada - nie myślałem o tym. Jeśli wszystko inne zawiedzie, przejrzę kod. Miałem nadzieję, że pojawią się wspólne wzorce, najlepsze praktyki, na które ktoś może mnie wskazać. – biscuit314

+0

Ponieważ kwerenda jest po prostu IQueryable i pozornie znasz opcje w czasie kompilacji, wydaje się, że możesz kontynuować układanie warunkowych predykatów na oryginalnym zapytaniu, aż będziesz gotowy do wykonania, prawda? W przypadku, gdy potrzebujesz manipulacji danymi przy wstawianiu, aktualizacji, usuwaniu, możesz dodać wyzwalacze, które są utrzymywane przez EF i w ostateczności po prostu zamapuj obiekt na przechowywany proc. –

Odpowiedz

1

Nie ma możliwości, według mojej wiedzy, zmodyfikować SQL, który jest generowany przez dostawcę EF.

Jednak w tych specjalnych przypadkach można uruchomić SQL bezpośrednio.

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

Musisz tylko upewnić się, że wszystko, co zwrócisz, pasuje do kształtu SomeEntity.

0

Wdrożenie Interceptor: EF-Tutorial

wygląda następująco:

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); 
      } 
     } 

Ale jak uzyskać typ uzyskać metadane nie wiem teraz.