不了解LinqPad中Dapper的动态查询结果

时间:2014-04-30 22:41:18

标签: dapper linqpad

我正在调查使用Dapper并在LinqPad中尝试过这个(你需要提供自己的连接字符串并设置一个'Ticket'表来实际运行它):

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 ---

如您所见,以下是奇怪的:

  • 它允许我访问第一个项目,但它不会转储而且不是null(??)并且有四个项目被返回。
  • 当我枚举时,如果我转换为IDictionary&lt; string,object&gt;,它就可以了。但枚举的实际项目(ticketObj)再次不为null,但我无法转储它。如果我尝试获取其类型,我会得到一个空引用异常。

如果我使用通用查询&lt; dynamic&gt;,则结果相同版本也是。

我认为动态结果应该是Expandos,我可以做类似

的事情
ticketObj.Status.Dump();

即。查询中的字段将转换为Query返回的每个对象的属性。我错过了什么?这对Dapper的动态特性有何影响?或者LinqPad可能无法使用动态对象?

2 个答案:

答案 0 :(得分:4)

这里有两个问题。第一个是LINQPad转储动态对象,将IDynamicMetaObjectProvider明确地实现为IDictionary<string,object>,而无需先旋转以获得更好的视图。这已经为下一次构建修复了。

第二个问题是,直接在Dump()上调用DapperRow会无声地失败,而不会抛出RuntimeBinderException人所期望的(&#39; DapperRow不包含&的定义) #34;转储&#34;&#39)。我认为,这是DapperRow的实施过程中的错误。

有许多解决方法。首先,正如您所发现的那样,首先是object。另一种解决方法是直接调用Dump扩展方法:

LINQPad.Extensions.Dump (ticketObj);

或:

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

另一个解决方法是调用Console.WriteLine,LINQPad重定向到Dump

Console.WriteLine (ticketObj);

答案 1 :(得分:0)

我已经确定这是一个LinqPad问题。由于它使用扩展方法,因此无法真正处理动态类型。但是,如果将动态转换为对象,则可以正常工作。所以如果你替换

firstTicket.Dump();

((object)firstTicket).Dump();

它有效......有点儿。它显示带有查询列的IDictionary。 LinqPad无法知道动态添加的列是什么。 See SO this answer了解更多信息。

这种技术在枚举中也有效。如果我改变

ticketObj.Dump();

((object)ticketObj).Dump();

它有效。我也可以访问动态属性,我只需要先抛出它们。

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

.GetType()似乎不适用于动态类型...我不认为他们有一个。请注意这是否正确,但这在普通的VS控制台应用程序中也不起作用。