Ninject 和 WCF Web 服务使实体框架变慢

Posted

技术标签:

【中文标题】Ninject 和 WCF Web 服务使实体框架变慢【英文标题】:Ninject and WCF Web Services make Entity Framework slow 【发布时间】:2019-10-02 06:16:27 【问题描述】:

我有下一个设置:在 IIS 中托管的 WCF Web 服务。 Entity Framework 6 用于从数据库中检索数据。 Web Services 在 Global.asax.cs 中初始化,它继承自 NinjectHttpApplication(所以我们使用 ninject 进行依赖注入)。在这个 NinjectHttpApplication 中,在 CreateKernel 方法上,我们将 EF DbContext 绑定如下:

protected override IKernel CreateKernel()

    var kernel = new StandardKernel();
    kernel.Bind<DbContext>().To<MyCustomContext>().InTransientScope();
    return kernel;

那么,每次调用一个服务,都会在它的构造函数中获取Context如下:

_context = kernel.Get<DbContext>();    

然后,服务从数据库中检索数据,如下所示:

data = _context.Set<TEntity>().Where(<whatever filter>);

话虽如此,我的问题是下一个:我有一个被多次调用的服务(一个复杂而长的查询和多个连接),每次调用它时,EF 都需要很长时间才能生成 SQL 来发送作为我编码的 Linq To 实体的结果到数据库。在数据库中执行查询没什么(600 毫秒),但每次调用此服务时,EF 都需要很长时间才能生成 SQL。我怀疑这是因为kernel.Bind&lt;DbContext&gt;().To&lt;MyContext&gt;().InTransientScope() 在每次有调用时都在强制 EF 创建 DbContext 的新实例。

我已经使用 UnitTests 进行了一些测试,但行为完全不同:如果您从同一个单元测试方法多次实例化服务并调用它,EF 仅第一次生成查询需要很长时间,然后从后续调用中生成 SQL 不需要任何时间(相同的查询,但使用不同的参数来过滤要检索的数据)。从单元测试来看,CreateKernel() 当然只在Initialize() 方法中调用一次(就像在global.asax.cs 中的Web 服务中一样),所以我不知道是什么引起了这个巨大的延迟。我怀疑 EF 能够保留/缓存使用单元测试方法预编译的查询,但不能保存在真正的 Web 应用程序中。有什么线索吗?

请注意,Linq to Entities 查询是参数化的(字符串和日期是参数)。

非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

我发现您将 DbContext 绑定在 InTransientScope 中,这意味着每次您从 ninject 获取 Dbcontext 时,它都会为您创建一个新的 DbContext。

您可以考虑使用 InThreadScope() 而不是 InTransientScope(),这意味着 ninject 在同一个线程中时将返回同一个实例。

还有 SingleTon 范围,这意味着总是返回相同的实例,但这会使 dbcontext 太大。

【讨论】:

谢谢,我已经尝试了这两种方法(单例和线程),它有助于“EF 预热”,但仍然需要很长时间才能将查询“翻译”为 SQL(在DB 是毫秒)。我已经阅读了有关预编译查询的信息:根据我阅读的文档,EF6 会自动执行此操作(当不包含“包含”方法时),但在我的情况下,每次 coz 需要很长时间时都会编译和生成查询。知道为什么吗?

以上是关于Ninject 和 WCF Web 服务使实体框架变慢的主要内容,如果未能解决你的问题,请参考以下文章

Ninject 3、WCF服务和参数化构造函数

无法让 Ninject 拦截与 WCF 一起使用

WCF Web API 和 WCF 数据服务之间的区别

WCF 数据服务或实体框架

无法使用实体框架更新记录并使用存储库模式进行 ninject

WCF 和 IIS 的实体框架问题