2014-04-30 46 views
0

我正在調查使用Dapper並在LinqPad中嘗試過(你需要提供自己的連接字符串並設置一個'Ticket'表來實際運行這個):不明白從Dapper動態查詢結果內LinqPad

using (var conn = new SqlConnection(builder.ToString())) 
{ 
    conn.Open(); 
    var loadSql = 
     @"Insert into Ticket(StatusKey, Status, ContactFirstName, ContactPhoneNumber, WorkflowKey) 
      Values (@statusKey, @status, @first, @phoneNumber, @key)"; 
    var values = new[] 
    { 
     new { statusKey = "O", status = "Open", first = "Bob", phoneNumber = "6855551425", key = "std" }, 
     new { statusKey = "R", status = "Researching", first = "Sue", phoneNumber = "77785552136", key = "exp" }, 
     new { statusKey = "OD", status = "Overdue", first = "Ted", phoneNumber = "6795551496", key = "std" }, 
     new { statusKey = "C", status = "Closed", first = "Mark", phoneNumber = "9945552678", key = "std" } 
    }; 
    "Rows Added".Dump(); 
    conn.Execute(loadSql, values).Dump(); 
    "".Dump(); 

    // Using <dynamic> returns same results 
    var tickets = conn.Query("Select Status, ContactFirstName, ContactPhoneNumber From Ticket").ToList(); 
    "Tickets Found".Dump(); 
    tickets.Count().Dump(); 
    "".Dump(); 

    "Attempt to get first ticket".Dump(); 
    var firstTicket = tickets[0]; 
    firstTicket.Dump(); 
    (firstTicket ?? "first ticket is null").Dump(); 
    "--- End First Ticket Attempt ---".Dump(); 
    "".Dump(); 

    "Access items returned by query".Dump(); 
    tickets.ForEach(ticketObj => 
    { 
      // ticketObj isn't null, but it not there either?? 
      " Try to dump enumerated ticket".Dump(); 
      if(ticketObj == null) " is null".Dump(); 
      ticketObj.Dump(); 
      //ticketObj.GetType().Dump(); // Null ref exception? 
      " --- End Enumeration Dump ---".Dump(); 

      // Have to cast to dictionary 
      var ticket = (IDictionary<string,object>)ticketObj; 
      string.Format(" {0}: {1} at {2}", ticket["Status"], ticket["ContactFirstName"], ticket["ContactPhoneNumber"]).Dump(); 

      "".Dump(); 
    }); 
    "--- End Access Test ---".Dump(); 
    "".Dump(); 


    conn.Execute("Truncate table ticket"); 
} 

我得到以下結果:

Rows Added 
4 

Tickets Found 
4 

Attempt to get first ticket 
--- End First Ticket Attempt --- 

Access items returned by query 
    Try to dump enumerated ticket 
    --- End Enumeration Dump --- 
    Open: Bob at 6855551425 

    Try to dump enumerated ticket 
    --- End Enumeration Dump --- 
    Researching: Sue at 77785552136 

    Try to dump enumerated ticket 
    --- End Enumeration Dump --- 
    Overdue: Ted at 6795551496 

    Try to dump enumerated ticket 
    --- End Enumeration Dump --- 
    Closed: Mark at 9945552678 

--- End Access Test --- 

正如你所看到的,下面是怪異:

  • 它讓我訪問第一個項目,但它不會轉儲並且不爲空(??),並且有四個項目被返回。
  • 當我列舉,如果我投到一個IDictionary <字符串,對象>,它的工作原理。但是枚舉的實際項目(ticketObj)仍然不爲空,但我無法轉儲它。如果我嘗試獲取它的類型,我會得到一個空引用異常。

如果我還使用通用查詢<動態>版本,結果也是一樣的。

我認爲這裏應該是expandos的動態效果,我可以做類似

ticketObj.Status.Dump(); 

即查詢中的字段將變成由Query返回的每個對象的屬性。我錯過了什麼?這是Dapper的動態特性是如何工作的?或者,也許LinqPad不適用於動態對象?

回答

4

這裏有兩個問題。首先,LINQPad轉儲實現IDynamicMetaObjectProvider明確爲IDictionary<string,object>的動態對象,而不首先轉向以獲得更好的視圖。這已被修復爲下一個版本。

第二個問題是直接在DapperRow上調用Dump()會自動失敗,而不是拋出RuntimeBinderException,人們會期望('DapperRow不包含「Dump」'的定義)。我認爲這是實施DapperRow時的一個錯誤。

有許多解決方法。第一個,如你所發現的,首先投給object。另一個解決方法是調用Dump擴展方法直接:

LINQPad.Extensions.Dump (ticketObj); 

或:

LINQPad.Extensions.Dump (ticketObj, "First ticket"); 

又一替代方法是調用Console.WriteLine,其LINQPad重定向到Dump

Console.WriteLine (ticketObj); 
+0

感謝您的優秀的解釋! –

0

我確定這是一個LinqPad問題。由於它使用擴展方法,因此它不能真正處理動態類型。但是,如果將動態投射到對象上,它就可以工作。所以,如果你有

((object)firstTicket).Dump(); 

更換

firstTicket.Dump(); 

它的工作原理......之類的。它使用查詢中的列顯示IDictionary。 LinqPad無法知道動態添加的列是什麼。 See SO this answer瞭解更多信息。

這同樣的技術也在枚舉中起作用。如果我改變

ticketObj.Dump(); 

((object)ticketObj).Dump(); 

它的工作原理。我也可以訪問動態屬性,我只需要先施放它們。

((string)ticketObj.Status).Dump(); 

.GetType()似乎不適用於動態類型...我不認爲它們有一個。請注意,如果這是正確的,但這在正常的VS控制檯應用程序中也不起作用。