我从 DbSet.Find() 调用中获得糟糕的性能。我的代码如下所示:
public class Area
{
[Key]
public string Id { get; protected set; }
// ...
}
public class MyContext : DbContext
{
//...
public DbSet<Area> Areas { get; set; }
//...
}
// This is the call that takes so long
Area area = context.Areas.Find(id);
我知道这必须搜索实体集、检查更改跟踪等,并且会触发对数据库的调用。问题是它比简单的 context.Areas.SingleOrDefault(x => x.Id == id)
调用需要更长的数量级。比我认为合理的多得多。根据另一个问题的提示,我也尝试过暂时关闭更改跟踪但没有成功(它似乎没有任何效果):
try
{
context.Configuration.AutoDetectChangesEnabled = false;
return context.Areas.Find(id);
}
finally
{
context.Configuration.AutoDetectChangesEnabled = true;
}
为了弄清真相,我启动了探查器。这是我发现的:
看起来它一直在准备执行计划。但是为什么这会在 .Find()
调用期间花费这么长时间而不是显式 .SingleOrDefault
调用(注意在调用堆栈顶部附近,它实际上是准备一个 SingleOrDefault
调用)。有什么方法可以查看 .Find()
方法实际尝试编译的查询吗?
最佳答案
我从来没有弄清楚为什么要花这么长时间。它生成的查询看起来很合理(只是一个简单的 SELECT
)。我正在使用一个非常复杂的域模型,虽然上面描述的 Area 实体是孤立且简单的,但 Entity Framework 可能以某种方式试图构建 View 或生成一个涉及域模型其他部分的查询(或者更确切地说,试图决定它不应该)。
无论如何,我确实制定了一个变通办法。诀窍是手动执行(我认为)Find()
调用首先执行的工作:
public Area FindArea(string id)
{
// First see if the DbSet already has it in the local cache
Area area = context.Areas.Local.SingleOrDefault(x => x.Id == id);
// Then query the database
return area ?? context.Areas.SingleOrDefault(x => x.Id == id);
}
可以使用扩展方法轻松推广此技术。此特定实现假定实体将其 ID 存储在字符串 Id
列中并实现以下接口(interface)。但是,通过一些调整,您可以使其适应各种领域模型。
public interface IEntityWithId
{
string Id { get; }
}
public static object FastFind<TEntity>(this DbSet<TEntity> dbSet, string id)
where TEntity : IEntityWithId, class
{
// First see if the DbSet already has it in the local cache
TEntity entity = dbSet.Local.SingleOrDefault(x => x.Id == id);
// Then query the database
return entity ?? dbSet.SingleOrDefault(x => x.Id == id);
}
关于c# - 简单的 DbSet<TEntity>.Find() 调用永远占用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16345114/