2011-02-28 35 views
26

我正在爲WinForms應用程序編寫查詢管理器,其中包括需要能夠在用戶輸入查詢時向用戶提供實時搜索結果的過程(想想谷歌的實時結果,儘管顯然是在一個厚厚的客戶端環境中而不是網絡上)。由於結果需要在用戶鍵入時開始到達,因此搜索將變得越來越具體,因此如果在用戶輸入更具體的信息時仍然執行查詢,我希望能夠取消查詢(因爲結果會無論如何,簡單地被丟棄)。取消實體框架查詢

如果這是普通的ADO.NET,我當然可以使用DbCommand.Cancel函數並完成它,但我們使用EF4來訪問數據,並且似乎沒有一種明顯的方法可以取消查詢。另外,在Reflector中打開System.Data.Entity並查看EntityCommand.Cancel可以看到一個令人沮喪的空方法體,儘管docs聲稱調用它會將它傳遞給provider命令的相應的Cancel函數。

我已經考慮過簡單地讓現有的查詢運行並且啓動一個新的上下文來執行新的搜索(並且只是在它完成時丟棄現有的查詢),但是我不喜歡單個客戶端的想法當我只對最近的結果感興趣時,運行並行查詢的多個開放數據庫連接。

所有這些讓我相信,一旦將EF查詢分派到數據庫後根本無法取消EF查詢,但我希望這裏的某個人能夠指出我忽略的一些內容。

TL/DR版本:是否可以取消當前正在執行的EF4查詢?

+0

我問的問題關於MSDN論壇這個問題:http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/ d5ea8036-73e5-4566-9407-fa7a6a5fca3c這個原始問題是關聯的。希望MS的某個人能夠提供另一種解決方案。 – 2011-03-01 12:23:23

回答

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

有趣;爲澄清一點,我並不建議用'EntityCommand'是正確的做法互動,但事實上,該方法體爲空意味着,它可能在一個更高的水平的可能性是渺茫到無。這是一個有趣的場景,最終可能會發揮作用,但現在我確實需要更改跟蹤,因此處理上下文並不是我準備做的事情。如果我找不到替代品,我會接受。 – 2011-02-28 21:45:55

+0

@Adam:好的,我會想想有更改跟蹤明天,因爲它有新的後果場景 - 即使你取消查詢所有載入的實例已經通過上下文進行跟蹤。我最初的建議是每個搜索的新上下文,但我必須考慮。 – 2011-02-28 22:30:22

+0

我並不是真的擔心在加載時取消查詢。用上面的方法很容易實現。我正在尋找的是在* query *階段取消它(當它執行服務器端時)。 – 2011-02-28 23:15:00