2014-10-27 46 views
8

如果我想訪問RDBMS特有的功能,該怎麼辦?有沒有一種方法將數據庫特定的SQL注入到由EF生成的SQL中?泄漏實體框架的抽象 - 只是一點

例如,在Oracle 12c中,你可以動態有效增加DDL和DML(有很多不同的,我會用在這裏只簡單的例子):

這可以很好地模擬了C#:

然後用LINQ

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

.AsOfPeriodFor擴展使用

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

可以是這樣的:

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

我的問題:是否有鉤子或IInterfaces可用於將這些RDBMS專業短語插入由EF生成的SQL中?或者將不得不與上面的定製Oracle DB Provider結婚?這種類型的東西是可能的嗎?你能指點我一個可以提供指導的博客/書籍/視頻/古茹嗎?

+1

是不是EF開源? – Ben 2014-10-27 22:10:45

+1

@Ben好點 - 我沒有想到這一點。如果一切都失敗了,我會查看代碼。我希望能有共同的模式,有人可以指出我的最佳做法。 – biscuit314 2014-10-27 22:22:11

+0

由於查詢只是一個IQueryable,而且您在編譯時似乎知道這些選項,所以您似乎可以繼續在原始查詢上堆疊條件謂詞,直到您準備好執行爲止,對吧?如果您在插入,更新和刪除時需要數據操作,則可以添加由EF維護的觸發器,並且作爲最後的手段,只需將該實體映射到存儲的proc。 – 2015-06-06 06:22:40

回答

1

據我所知,沒有辦法修改EF提供者生成的SQL。

但是,對於這些特殊情況,您可以直接運行SQL。

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

你只需確保你返回的任何東西匹配SomeEntity的形狀。

0

實現一個攔截器: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); 
      } 
     } 

可是如何才能讓該類型得到我不知道現在的元數據。