【问题标题】:EF6 - not doing what I expected for .Any()EF6 - 没有做我对 .Any() 的期望
【发布时间】:2017-04-24 09:13:00
【问题描述】:

我被 EF 6 难住了……我有一个 Web 应用程序,它在性能方面表现得非常糟糕。在分析时,我发现其中一个罪魁祸首是我的一种方法,它检查 EF6 实体上的集合是否为空(或不为空)。

基本上,我有:

public partial class BaseEntity
{
    public int BaseEntityId { get; set; }
    public string Name { get; set; }

    // a few more properties, of no concern here....

    // a lazily loaded collection of subitems        
    public virtual ICollection<Subitem> Subitems { get; set; }
}

public partial class Subitem
{
    public int SubitemId { get; set; }
    public int BaseEntityId { get; set; }
    public string Name { get; set; }

    // a few more properties, of no concern here....
}

在我的应用程序中,我需要检查BaseEntity 的给定实例是否为“空” - 这被定义为没有子项。所以我将这个方法CheckIfEmpty 添加到第二个部分类文件中:

public partial class BaseEntity
{
    public bool IsEmpty 
    {
        return !Subitems.Any();
    }
}        

现在一个BaseEntity 可以有成百上千个子项——所以我想用最有效的方法来检查是否有任何子项。我的假设是对尚未从数据库加载的集合调用 .Any() 基本上会转化为

IF EXISTS(SELECT * FROM dbo.Subitems) ......

SQL 调用 - 或类似的东西 - 只是检查是否存在任何项目 - 或不存在。我特别选择了.Any() 而不是.Count &gt; 0,因为我知道检查计数需要枚举整个集合,因此当我只想知道是否存在(或不存在)任何项目时效率非常低。

不需要知道有多少存在,我也不对它们的详细信息感兴趣 - 只需简单的 YESNO is empty? 问题就足够了。

令我大吃一惊(和眼花缭乱),事实证明 EF6 将这个简单的 .Any() 调用转换为加载 整个集合的 SELECT 语句! - 这绝对是 NOT我所讨价还价的……

那么有没有什么简单的方法可以简单地检查一个尚未加载的集合是否有任何值——没有从数据库加载完整的集合? ?

【问题讨论】:

  • 调用Subitems 会在到达.Any 之前加载所有项目,这就是延迟加载的实现方式。第一次访问Subitems 时,它会被加载。我尝试从不使用延迟加载,但这确实使我的代码复杂化:我倾向于尽快关闭上下文,并为db.Subitem.Any(si=&gt;si. BaseEntityId == ...)打开另一个上下文
  • SubItems 是一个ICollection。如果它是IQueryable,它可能会按您的预期工作(不过我不确定,我不知道延迟加载是否可以与IQueryable 一起使用)
  • 通过使用 Eager 加载方法并查询 DbSet,你会得到你想要的:context.Set().Any();翻译成:SELECT CASE WHEN EXISTS (SELECT 1 FROM [TEntity] AS [m]) THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END
  • msdn 上的文档有一些解决方案:msdn.microsoft.com/en-us/library/…
  • @alessalessio:谢谢-从未想过以这种方式“反转”检查-但您是 100% 正确的-这样,EF 的行为与我预期的一样,并进行了简单的IF EXISTS() 检查和表现非常好 - 谢谢!

标签: c# sql-server entity-framework-6 asp.net-4.5


【解决方案1】:

通过使用 Eager 加载方法并查询 DbSet,您将得到您想要的:

context.Set&lt;TEntity&gt;().Any();

翻译成:

SELECT CASE WHEN EXISTS ( SELECT 1 FROM [TEntity] AS [m]) THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END

【讨论】:

  • 再次感谢 - 很好的回答。我稍微修改了它以使用context.Subitems.Any(si =&gt; si.BaseEntityId == 42);,这也很好用。很好的方法 - 谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-14
  • 1970-01-01
  • 2013-12-14
  • 1970-01-01
  • 2019-07-22
  • 1970-01-01
  • 2015-05-30
相关资源
最近更新 更多