2016-08-18 83 views
3

是好以包裹LINQ 2 SQL查詢到Task.Run方法如下所示LINQ到通過纏繞在Task.Run(LINQ查詢在多線程SQL)

var keywordlistquery = await Task.Run(() => 
     { 
      using (DataContext context = new DataContext(connection)) 
      { 
       context.ObjectTrackingEnabled = false; 
       return from keyword in context.GetTable<KeywordsList>() 
         select new 
         { 
          keyword.search_text, 
          keyword.search_keyword 
         }; 
      } 
     }); 

是對上述代碼的線程安全,在生產過程中會有什麼問題。是否有更好的方法來編寫上面的代碼。

+1

這將無法正常工作,因爲您返回的是Queryable,而不是結果。當您嘗試訪問結果時,關閉上下文。無論如何,實體框架alreay具有異步操作,因此嘗試讓L2S異步運行沒有多大意義。 ToListAsync();' –

+0

這是Linq to SQL代碼,所以沒有任何內置的異步方法。 –

回答

2

這裏的一個很好的答案很大程度上取決於代碼的意圖是什麼。

一般來說,請記住Linq to SQL技術是在.NET中實現本地異步和等待模式之前建立的,然後停止使用。

因此,除非您對手動維護異步任務感到非常舒服,否則根本不要嘗試對Linq to SQL使用異步。可能的情況是,除非服務器需要處理非常高的請求併發性,否則你不會獲得太多的性能提升,但是手動清理異步任務是一種真正難以發現的錯誤方式,最終會意外阻止請求線程。

如果您確實需要像這樣處理代碼中的異步,那麼有幾個解決方案。

首先明白上面的代碼創建一個查詢,但不執行它。它返回的是一個IQuerable ...基本上,將其視爲一個尚未運行的SQL語句。直到像ToArray或ToList這樣的方法被調用,或者直到它在foreach循環或類似環境中使用,Linq to SQL纔會運行查詢。

而且,當您使用返回語句時,使用這種匿名類型很難。您可能需要創建DTO類並使用選擇投影來實例化它們

其次,您正在將上下文封裝在using塊中(這是一種很好的做法),但是如果在實際執行之前返回查詢上下文得到處置。調用者將得到一個IQueryable,但是當它試圖使用它時,你將最終得到一個異常,因爲上下文已經被處置。

所以....這裏有兩個選擇取決於這個代碼是要返回實際數據,還是返回一個查詢,然後調用者可以進一步修改。

案例1)返回數據:這裏

public async Task<object> DoThings(CancellationToken token) 
{ 
    var keywordlistquery = await Task.Run(() => 
    { 
     using (var context = new DataClasses1DataContext()) 
     { 
      context.ObjectTrackingEnabled = false; 
      return from keyword in context.GetTable<KeywordsList>() 
        select new 
        { 
         keyword.search_text, 
         keyword.search_keyword 
        }; 
     } 
    }, token); 
    return keywordlistquery; 
} 

注意,這個方法本身應該是異步的,你應該總是試圖儘可能使用取消標記。這會調用ToArray來強制查詢立即執行並返回數據。請記住,這將返回整個表。如果調用者想要提供where子句或其他任何東西,代碼仍將加載所有數據。

案例2:返回IQuerable

在第二種情況下,你希望你的方法只返回查詢。這樣,調用者可以在執行前修改查詢。這允許調用者添加語句以包含where子句或排序結果或其他內容;並將這些語句包含在生成的TSQL中。

在這種情況下,技巧是調用者必須控制數據上下文的生命週期,並且由於該方法實際上並不執行結果,所以它不需要是異步的。

public async Task CallingMethod() 
{ 
    using (var context = new DataClasses1DataContext()) 
    { 
     var token = new CancellationToken(); 
     context.ObjectTrackingEnabled = false; 
     var query = DoThings(context); 
     var result = await Task.Run(() => query.ToArray(), token); 
    } 
} 

public IQueryable<object> DoThings(DataContext context) 
{ 
    var keywordlistquery = from keyword in context.GetTable<KeywordsList>() 
     select new 
     { 
      keyword.search_text, 
      keyword.search_keyword 
     }; 
    return keywordlistquery; 
} 

正如我前面提到的那樣,選擇新的anonynous在這種情況下不起作用。最好創建一個DTO類並選擇一個新類,或者返回整個表。