Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有办法拦截所有Linq到SQL查询?_Linq_Linq To Sql_Interception - Fatal编程技术网

有没有办法拦截所有Linq到SQL查询?

有没有办法拦截所有Linq到SQL查询?,linq,linq-to-sql,interception,Linq,Linq To Sql,Interception,我已经构建了一些可以重建表达式树的代码,这样我就可以避免触发不受支持的转换为SQL异常,只要调用我的函数替换iqueryable,它就可以正常工作。问题是,我希望它能够自动应用于我项目中的所有查询,而不必担心对每个查询单独调用此函数。有什么办法可以让我截获一切吗 我尝试使用Reflection.Emit创建包装提供程序,并在数据上下文中使用Reflection替换它,结果发现,即使使用Reflection.Emit,我也无法实现内部IProvider接口 我还尝试用基于RealProxy的类替换

我已经构建了一些可以重建表达式树的代码,这样我就可以避免触发不受支持的转换为SQL异常,只要调用我的函数替换iqueryable,它就可以正常工作。问题是,我希望它能够自动应用于我项目中的所有查询,而不必担心对每个查询单独调用此函数。有什么办法可以让我截获一切吗

我尝试使用Reflection.Emit创建包装提供程序,并在数据上下文中使用Reflection替换它,结果发现,即使使用Reflection.Emit,我也无法实现内部IProvider接口

我还尝试用基于RealProxy的类替换提供程序,该类适用于非编译查询,但CompiledQuery.Execute方法引发异常,因为它不会强制转换到SqlProvider类。我尝试用另一个代理替换提供程序上对Compile方法的响应,以便截获Execute调用,但未能检查返回类型是否正确


我对使用我已经尝试过的任何其他想法或方法持开放态度?

如果不查看您的代码,很难判断这是否是一个适用的解决方案,但是如果您有一个DI友好的应用程序体系结构,您可以实现一个拦截器,并让您最喜欢的IoC容器在运行时为您发出合适的类型

深奥的?一点考虑这样的界面:

public interface ISomeService
{
     IEnumerable<SomeEntity> GetSomeEntities();
     // ...
}
public class SomeService : ISomeService
{
     private readonly DbContext _context // this is a dependency!
     private readonly IQueryTweaker _tweaker; // this is a dependency!

     public SomeService(DbContext context, IQueryTweaker tweaker) // this is constructor injection!
     {
         _context = context;
         _tweaker = tweaker;
     }

     public IEnumerable<SomeEntity> GetSomeEntities()
     {
         return _tweaker.TweakTheQuery(_context.SomeEntities).ToList();
     }
}
下一步是配置IoC容器,以便它知道在类型的构造函数需要ISomeService时注入SomeService实现:

此时,您已经准备好配置拦截-

但在跳进兔子洞之前,你们应该先看看装饰器和拦截器是如何关联的

关键的一点是,您并没有截取LINQ to SQL或.NET framework本身内部的任何内容-您截取的是您自己的方法调用,用您自己的代码包装它们,并且在任何像样的IoC容器的帮助下,您将截取对调用LINQ to SQL的方法的调用,而不是直接调用Linq到SQL本身。从本质上讲,IQueryTweaker依赖项变成了拦截器类的依赖项,您只需对其用法编写一次代码

关于DI拦截,一个有趣的事情是,可以组合拦截器,这样您就可以在AuditServiceInterceptor之上,在CircuitBreakerServiceInterceptor之上有一个ExecutionTimerServiceInterceptor。。。最好的一点是,您可以配置您的IoC容器,这样您就可以完全忘记它的存在。当您向应用程序添加更多服务类时,您所需要做的就是遵循您定义的命名约定,您刚刚编写了一个服务,它不仅可以完成您刚刚编写的所有严格与数据相关的任务,而且还可以在数据库服务器关闭时自动禁用3分钟,并在备份之前保持禁用状态;该服务还记录所有插入、更新和删除,并将其执行时间存储在数据库中以进行性能分析。这个词似乎合适


这种技术——拦截——可以用来解决交叉问题;解决这些问题的另一种方法是通过AOP,尽管Mark Seeman的优秀著作清楚地说明了AOP框架是如何比DI拦截更不理想的解决方案。

查看DI拦截;并非所有IoC容器都支持它,您可以尝试使用Ninject。我想它能满足你的需要。只是快速浏览了Ninject,我不确定你认为它会有什么帮助?我还没有看到你的代码,但从我掌握的情况来看,你有一个方法,你需要以自动方式包装在另一个方法中,这正是DI拦截可以为你做的。我不是在我的手机上发布详细信息,但当我进入我的电脑时,我会扩展思路:我想可能可以对所有iQueryTables包装GetEnumerator调用,以便它生成一个新的iQueryTable并从中返回枚举器。我没有考虑过这种方法,但是当.NET方法也调用GetEnumerator时,它也需要这样做,我可能不希望它对实际上没有调用GetEnumerator的IQueryables这样做-例如,当它们自己被查询时。虽然我不熟悉DI,所以我可以在如何进行这方面提供一些帮助。我对DI拦截并不十分熟悉,但我认为这不会起作用。据我所知,这里的GetSomeEntities调用是我必须显式调用的,但是这些查询是由Linq to SQL中的内部.NET framework类支持的iquable构建的,然后在大多数情况下由内部.NET代码执行。我没有显式地调用GetSomeEntities——在某些情况下,它可能是一个方法,如ToList、First或Single,但在其他情况下,我使用F循环通过IQueryable 或隐式调用其上的GetEnumerator的每个。
public class SomeService : ISomeService
{
     private readonly DbContext _context

     public SomeService(DbContext context)
     {
         _context = context;
     }

     public virtual IEnumerable<SomeEntity> GetSomeEntities()
     {
         return _context.SomeEntities.ToList();
     }
}
_kernel.Bind<ISomeService>().To<SomeService>();