マイクの記事をご覧ください。これはあなたに役立つかもしれません。
http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2007/12/06/10008.aspx
私は非同期的にSQLクエリにLINQを実行する方法について最近質問を見ました。
クエリをThreadPoolにプッシュする "偽の非同期"ルートを使用しない場合は、DataContextのGetCommand()メソッドを使用して実際の非同期作業を実行してから、自分で作業を行うことができます。
したがって、これは同期的には次のようになります。
using (NorthwindDataContext ctx = new NorthwindDataContext())
{
ctx.Connection.Open();
var query = from c in ctx.Customers
where c.Country == "Spain"
select c;
using (SqlCommand command = ctx.GetCommand(query) as SqlCommand)
{
using (SqlDataReader reader = command.ExecuteReader())
{
foreach (Customer c in ctx.Translate<Customer>(reader))
{
Console.WriteLine(c.CustomerID);
}
}
}
}
ここでは、匿名型ではなく、具体的な型をここから取得しています。私がここに書いたように、私は匿名のタイプで翻訳することはできないと私は考えています。
したがって、これを非同期に実行するものに分割するには、次のようなことがあります。私たちは同期と非同期ピース(私はそれが正しい:-)だと主張していないよということに注意してください)にそれを分割する方法の線に沿って何かあるかもしれない
using (NorthwindDataContext ctx = new NorthwindDataContext())
{
ctx.Connection.Open();
var query = from c in ctx.Customers
where c.Country == "Spain"
select c;
using (SqlCommand command = ctx.GetCommand(query) as SqlCommand)
{
SqlDataReader reader = null;
ManualResetEvent waitEvent = new ManualResetEvent(false);
command.BeginExecuteReader(result =>
{
try
{
reader = command.EndExecuteReader(result);
}
catch (SqlException ex)
{
Console.WriteLine("Sorry {0}", ex.Message);
}
finally
{
waitEvent.Set();
}
}, null);
waitEvent.WaitOne();
if (reader != null)
{
foreach (Customer c in ctx.Translate<Customer>(reader))
{
Console.WriteLine(c.CustomerID);
}
}
}
}
。
あなたのために仕事をしてくれた何らかの拡張メソッドにそれをラップすることができたらうれしいかもしれません。あなたはそのようなことをするかもしれないDataContext.BeginQuery(IQueryable)とDataContext.EndQueryを想像することができます。
私は、次のような少しのものを一緒にハッキングしました(壊れやすいので、大きなピンチで取ってください)。
namespace AsyncExtensions
{
public static class AsyncExtensions
{
private class AsyncResult : IAsyncResult
{
public AsyncResult()
{
doneEvent = new ManualResetEvent(false);
}
public object AsyncState
{
get { return (state); }
set { state = value; }
}
public WaitHandle AsyncWaitHandle
{
get { return (doneEvent); }
}
public bool CompletedSynchronously
{
get { return (false); }
}
public bool IsCompleted
{
get { return (completed); }
}
public void Complete()
{
completed = true;
doneEvent.Set();
}
public Exception Exception { get; set; }
public SqlDataReader Reader { get; set; }
private object state;
private bool completed;
private ManualResetEvent doneEvent;
}
public static IAsyncResult BeginQuery(this DataContext ctx, IQueryable query,
AsyncCallback callback, object state)
{
AsyncResult localResult = new AsyncResult();
localResult.AsyncState = state;
SqlCommand command = ctx.GetCommand(query) as SqlCommand;
command.BeginExecuteReader(result =>
{
try
{
SqlDataReader reader = command.EndExecuteReader(result);
localResult.Reader = reader;
}
catch (Exception ex)
{
// Needs to be rethrown to the caller...
localResult.Exception = ex;
}
finally
{
// Need to call the caller...
localResult.Complete();
if (callback != null)
{
callback(localResult);
}
}
}, null);
return (localResult);
}
public static IEnumerable<T> EndQuery<T>(this DataContext ctx,
IAsyncResult result)
{
AsyncResult localResult = (AsyncResult)result;
if (localResult.Exception != null)
{
throw localResult.Exception;
}
return (ctx.Translate<T>(localResult.Reader));
}
}
}
これで私はこのようなものをもう少し呼び出すことができました。
using (NorthwindDataContext ctx = new NorthwindDataContext())
{
ctx.Connection.Open();
var query = from c in ctx.Customers
where c.Country == "Spain"
select c;
ctx.BeginQuery(query, result =>
{
foreach (Customer c in ctx.EndQuery<Customer>(result))
{
Console.WriteLine(c.CustomerID);
}
}, null);
Console.ReadLine();
}
そのコードが破損する可能性が(私はそれについてあまりにも長い間考えをかけていない)、それは確かに、それは別のスレッドで、あなたのAsyncCallbackを呼ぶことにしますので、あなたがあなたのDataContextを保護する上で注意が必要になることを想定し、覚えておいてくださいあなたがBeginQuery()を呼び出すものよりも、DataContextでその拡張機能EndQueryを使用する際に注意が必要です。
また、ここでは、SubmitChanges()の呼び出しの一部として挿入/更新/削除操作を非同期的に実行する方法がありますが、これを使用する以外の方法がないと思いますそれをThreadPoolにプッシュするためのメカニズム(ここでは、DataContextに注意を払う必要があります)。
アップデート1
私は少し周りを頼み、私は匿名型の列挙ではなく、具体的なタイプを生成する1つの方法を見つけました。
AsyncExtensionsクラスに追加のメソッドを追加しました。
public static IEnumerable<T> EndQuery<T>(this DataContext ctx,
IAsyncResult result,
Func<IDataRecord, T> selector)
{
AsyncResult localResult = (AsyncResult)result;
if (localResult.Exception != null)
{
throw localResult.Exception;
}
IEnumerable<T> results =
(localResult.Reader.Cast<IDataRecord>()).Select(selector);
return (results);
}
次に、このように呼び出すことができます。
using (NorthwindDataContext ctx = new NorthwindDataContext())
{
ctx.Connection.Open();
var query = from c in ctx.Customers
where c.Country == "Spain"
select c;
ctx.BeginQuery(query, result =>
{
foreach (var v in ctx.EndQuery(result,
x => new {
Id = (string)x["CustomerID"],
Name = (string)x["CompanyName"]
}))
{
Console.WriteLine(v);
}
}, null);
Console.ReadLine();
}
だから、それは私が私もそれは少しだので、私のSqlDataReaderのは、ここで簡単に見てとることながら、閉じ取得されていないことを発見し
:-(それをやった方法は、非常にきれいではありません"EndQuery"メソッドが読者と一緒に本当に復帰する必要があることを考えれば、私はそれについて何をしているのかは十分には分かっていないので、少し考えてみる必要があります。この1つの上に:-)
私は404エラーを取得します... –