這裏的一個很好的答案很大程度上取決於代碼的意圖是什麼。
一般來說,請記住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類並選擇一個新類,或者返回整個表。
這將無法正常工作,因爲您返回的是Queryable,而不是結果。當您嘗試訪問結果時,關閉上下文。無論如何,實體框架alreay具有異步操作,因此嘗試讓L2S異步運行沒有多大意義。 ToListAsync();' –
這是Linq to SQL代碼,所以沒有任何內置的異步方法。 –