取消实体框架查询

时间:2011-02-28 15:30:12

标签: entity-framework entity-framework-4

我正在为WinForms应用程序编写查询管理器,除此之外,还需要能够在用户输入查询时向用户提供实时搜索结果(想想G​​oogle的实时结果)虽然显然是在厚厚的客户端环境而不是网络上)。由于结果需要在用户输入时开始到达,搜索将变得越来越具体,所以我希望能够在用户输入更具体的信息时仍然执行时取消查询(因为结果会无论如何,只是被丢弃。)

如果这是普通的ADO.NET,我显然可以使用DbCommand.Cancel函数并完成它,但我们使用EF4进行数据访问并且似乎没有明显的方法取消查询。另外,在Reflector中打开System.Data.Entity并查看EntityCommand.Cancel会显示一个令人沮丧的空方法体,尽管docs声称调用它会将其传递给提供者命令的相应Cancel功能

我考虑过简单地让现有的查询运行并启动一个新的上下文来执行新的搜索(并且一旦完成就处理现有的查询),但我不喜欢单个客户端有一个当我只对最近的结果感兴趣时,运行并行查询的大量开放数据库连接。

所有这一切都让我相信,一旦将EF查询分派到数据库中就没有办法取消EF查询,但我希望这里有人可以指出我忽略的东西。< / p>

TL / DR版本:是否可以取消当前正在执行的EF4查询?

1 个答案:

答案 0 :(得分:12)

看起来你在EF中发现了一些错误,但是当你向MS报告它时,它将被视为文档中的错误。无论如何,我不喜欢直接与EntityCommand进行交互的想法。以下是我如何杀死当前查询的示例:

var thread = new Thread((param) =>
    {
        var currentString = param as string;

        if (currentString == null)
        {
            // TODO OMG exception
            throw new Exception();
        }

        AdventureWorks2008R2Entities entities = null;
        try // Don't use using because it can cause race condition
        {
            entities = new AdventureWorks2008R2Entities();

            ObjectQuery<Person> query = entities.People
                .Include("Password")
                .Include("PersonPhone")
                .Include("EmailAddress")
                .Include("BusinessEntity")
                .Include("BusinessEntityContact");
            // Improves performance of readonly query where
            // objects do not have to be tracked by context
            // Edit: But it doesn't work for this query because of includes
            // query.MergeOption = MergeOption.NoTracking;

            foreach (var record in query 
                .Where(p => p.LastName.StartsWith(currentString)))
            {
                // TODO fill some buffer and invoke UI update
            }
        }
        finally
        {
            if (entities != null)
            {
                entities.Dispose();
            }
        }
    });

thread.Start("P");
// Just for test
Thread.Sleep(500);
thread.Abort();

这是我在30分钟后玩的结果,所以它可能不是应该被视为最终解决方案的东西。我发布它至少得到一些反馈,解决了这个解决方案可能引起的问题。要点是:

  • 上下文在线程
  • 内处理
  • 上下文未跟踪结果
  • 如果您终止线程,则终止查询并处理上下文(已释放连接)
  • 如果在开始新线程之前终止线程,则应该仍使用一个连接。

我检查过该查询是在SQL事件探查器中启动和终止的。

修改

顺便说一下。另一种简单地停止当前查询的方法是在枚举中:

public IEnumerable<T> ExecuteQuery<T>(IQueryable<T> query)
{
    foreach (T record in query)
    {
        // Handle stop condition somehow
        if (ShouldStop())
        {
            // Once you close enumerator, query is terminated
            yield break;
        }
        yield return record;
    }
}