2012-04-02 98 views
1

我正在尋找一種方法來調用與Linq的存儲過程,除非它是異步執行的。使用來自Microsoft網站的示例。有沒有辦法使用Linq到SQL存儲過程異步調用

[Function(Name="dbo.VariableResultShapes")] 
[ResultType(typeof(VariableResultShapesResult1))] 
[ResultType(typeof(VariableResultShapesResult2))] 
public IMultipleResults VariableResultShapes([Parameter(DbType="Int")] System.Nullable<int> shape) 
    { 
     IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), shape); 
     return ((IMultipleResults)(result.ReturnValue)); 
    } 

我這樣做與其他特效類似,並使用ResultType屬性映射我的調用結果。但是有沒有辦法以異步的方式調用它。我似乎無法找到任何有效的結果。

回答

0

爲什麼不只是使用TPL。這很簡單,但你可以看看PLINQ methods。如果TPL是確定的,那麼你可以做這樣的事情(僞ISH):

var task = Task.Factory.StartNew<IEnumerable<SQLPoco>(()=>{return SOMELINQTOSQL;}); 
task.ContinueWith((previousTask)=>{USE previousTask.Result;}); 
1

看看邁克在這裏的文章,這可能會幫助你。

http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2007/12/06/10008.aspx

我最近看到有關如何異步執行一個LINQ to SQL查詢的問題。

除非您想要將查詢推送到ThreadPool上的「假異步」路徑,您可以(AFAIK)使用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(); 
    } 

記住,代碼可能被打破(我沒有花這件事太長時間思考),它當然假設你會在保護您的DataContext小心,因爲它會調用在不同的線程您的AsyncCallback而不是你調用BeginQuery()的那個,這意味着你需要關心在DataContext上使用該擴展EndQuery。

此外,這裏的其他領域將是如何作爲對SubmitChanges()的調用的一部分異步執行任何插入/更新/刪除操作,我認爲除了使用一個以外的其他方法的機制將其推入ThreadPool(您仍然需要關注DataContext)。

更新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」方法需要在讀者仍然打開的情況下真正返回,所以這需要一些思考 - 也許是時候給在這一個:-)

+0

我得到一個404錯誤... – 2012-04-02 14:21:10

相關問題