取消实体框架查询

Ada*_*son 27 entity-framework entity-framework-4

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

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

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

所有这一切都让我相信,一旦将EF查询分派到数据库中就没有办法取消EF查询,但是我希望这里的某个人能够指出我忽略的东西.

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

Lad*_*nka 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();
Run Code Online (Sandbox Code Playgroud)

这是我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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • [为什么会尝试/最终而不是"使用"声明有助于避免竞争条件?](http://stackoverflow.com/questions/14830534/why-would-try-finally-rather-than-a-using-statement -help - 避免-A-种族conditio) (4认同)