取消实体框架查询 [英] Cancelling an Entity Framework Query

查看:143
本文介绍了取消实体框架查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为一个WinForms应用程序编写一个查询管理器,除了别的以外,还需要能够在用户输入查询时向用户提供实时搜索结果(认为Google的实时结果,虽然显然在一个厚实的客户端环境而不是网络)。由于结果需要以用户类型开始到达,因此搜索将变得越来越具体,因此,如果用户输入更具体的信息(如果结果将会被执行),我希望能够取消查询如果这是普通的ADO.NET,我显然可以使用 DbCommand.Cancel 函数并完成它,但是我们使用EF4进行数据访问,并不是一个明显的方法来取消查询。另外,在Reflector中打开System.Data.Entity并查看 EntityCommand.Cancel 显示了一个令人沮丧的空方法体,尽管 docs ,声称调用它会传递给提供者命令的相应的取消函数。



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



所有这一切使我相信,一旦将EF查询发送到数据库,根本就没有办法取消EF查询,但是我希望有人可能会指出



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

解决方案

看起来你在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 //不要使用,因为它可以导致竞争条件
{
entities = new AdventureWorks2008R2Entities ();

ObjectQuery< Person> query = entities.People
.Include(Password)
.Include(PersonPhone)
.Include( EmailAddress)
.Include(BusinessEntity)
.Include(BusinessEntityContact);
//提高readonly查询的性能,其中
//对象不必是由上下文
跟踪//编辑:但是它不适用于此查询,因为include
// query.MergeOption = MergeOption.NoTracking;

foreach(查询中的var记录
.Where(p => p.LastName.StartsWith(currentString)))
{
// TODO填充一些缓冲区并调用UI更新
}
}
finally
{
if(entities!= null)
{
entities.Dispose();
}
}
});

thread.Start(P);
//只是为了测试
Thread.Sleep(500);
thread.Abort();

如果在30分钟后,我是玩的结果,所以这可能不是应该考虑的事情作为最终解决方案我发布它至少得到一些反馈,可能由此解决方案引起的问题。要点是:




  • 上下文在线程内处理

  • 结果不被上下文追踪

  • 如果你杀死线程查询被终止并且上下文被排除(连接释放)

  • 如果你在启动新线程之前杀死线程,你应该使用仍然有一个连接。



我检查了该查询是在SQL分析器中启动和终止的。



编辑:



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

  public IEnumerable< T>执行查询< T>(IQueryable< T>查询)
{
foreach(查询中的T记录)
{
//处理停止条件某种方式
if(ShouldStop )
{
//一旦关闭枚举器,查询被终止
yield break;
}
yield return record;
}
}


I'm in the process of writing a query manager for a WinForms application that, among other things, needs to be able to deliver real-time search results to the user as they're entering a query (think Google's live results, though obviously in a thick client environment rather than the web). Since the results need to start arriving as the user types, the search will get more and more specific, so I'd like to be able to cancel a query if it's still executing while the user has entered more specific information (since the results would simply be discarded, anyway).

If this were ordinary ADO.NET, I could obviously just use the DbCommand.Cancel function and be done with it, but we're using EF4 for our data access and there doesn't appear to be an obvious way to cancel a query. Additionally, opening System.Data.Entity in Reflector and looking at EntityCommand.Cancel shows a discouragingly empty method body, despite the docs claiming that calling this would pass it on to the provider command's corresponding Cancel function.

I have considered simply letting the existing query run and spinning up a new context to execute the new search (and just disposing of the existing query once it finishes), but I don't like the idea of a single client having a multitude of open database connections running parallel queries when I'm only interested in the results of the most recent one.

All of this is leading me to believe that there's simply no way to cancel an EF query once it's been dispatched to the database, but I'm hoping that someone here might be able to point out something I've overlooked.

TL/DR Version: Is it possible to cancel an EF4 query that's currently executing?

解决方案

Looks like you have found some bug in EF but when you report it to MS it will be considered as bug in documentation. Anyway I don't like the idea of interacting directly with EntityCommand. Here is my example how to kill current query:

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();

It is result of my playing with if after 30 minutes so it is probably not something which should be considered as final solution. I'm posting it to at least get some feedback with possible problems caused by this solution. Main points are:

  • Context is handled inside the thread
  • Result is not tracked by context
  • If you kill the thread query is terminated and context is disposed (connection released)
  • If you kill the thread before you start a new thread you should use still one connection.

I checked that query is started and terminated in SQL profiler.

Edit:

Btw. another approach to simply stop current query is inside enumeration:

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;
    }
}

这篇关于取消实体框架查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆