2014-10-27 25 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); 
      } 
     } 

可是如何才能让该类型得到我不知道现在的元数据。