Dapper return 可以映射对象和其他非映射值吗?

Can Dapper return mapped object & other non mapped values?

我有这个 working sample 使用 dapper 的查询(实际上我使用的是真实的 table):

async void Main()
{
    var sql = @"SELECT PersonId = 1,
                FirstName = 'john',
                LastName = 'Lennon'";
    using (var conn = new SqlConnection(@"Data Source=....;Initial Catalog=W...."))
    {
        var person = await conn.QueryAsync<Person>(sql);
          person.Dump();
    }
}


public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

结果:

所以映射按预期工作。但有时我会查询 return 另一个值,例如:

SELECT PersonId = 1,
       FirstName = 'john',
       LastName = 'Lennon' , 
       cnt=(SELECT COUNT(1) FROM INFORMATION_SCHEMA.COLUMNS) //example

这是完全合法的:

问题:

是否可以return一个Person对象其他非映射值(在同一个select

类似于:

 await conn.QueryAsync<Person,int>(sql)

一个真实的例子:

SELECT  [AddressId]
      ,[PersonName]
      ,[Street]
      ,[Address_2]
      ,[House] , 
       cnt=(COUNT(1) OVER (PARTITION BY house)  )
  FROM [WebERP].[dbo].[App_Address]

所以我 return 一个 Address 对象,其计数与 table 相同,我不想要另一个 select.

是的,您可以为此使用 QueryMultiple 扩展名。但是您应该使用单独的 select 来获取列数:

SELECT PersonId = 1, FirstName = 'john', LastName = 'Lennon'
SELECT COUNT(1) FROM INFORMATION_SCHEMA.COLUMNS) 

然后得到两个结果

using(var result = sqlConnection.QueryMultiple(sql))
{
    var person = result.Read<Person>().Single();
    int count = multi.Read<int>().Single();
}

进一步阅读:Multiple Results部分。

另一种return附加值的方法是动态查询。但在那种情况下,您将不得不手动构建 Person 对象:

var sql = @"SELECT PersonId = 1,
            FirstName = 'john',
            LastName = 'Lennon',
            cnt=(SELECT COUNT(1) FROM INFORMATION_SCHEMA.COLUMNS)";
var row = conn.Query(sql).Single();
var person = new Person { 
    PersonId = row.PersonId, 
    FirstName = row.FirstName, 
    LastName = row.LastName
};
int cnt = row.cnt;

据我所知,没有其他方法可以 return 人和 cnt。

最简单的方法是将 cnt 添加到您的 Person class。您当然可以将其重命名为更有意义的名称。使它成为一个可为 null 的 int,以便根据它在数据集中的存在来设置或不设置它。

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int? cnt { get;set; }
}

现在,这个 cnt 并不真正属于这个人 class,但通常你不会将数据集分配给这样的 class,你会将它分配给 DTO 之类的东西,然后将其映射到您拥有的任何模型 class 或 classes 中,并以您认为合适的方式使用额外的属性。这将使您的业务 classes(例如 Person)保持纯净。

您确定要这样做吗?正如歌曲所说,保持生活中阳光的一面。 A​​ 查询应该有 a return 类型。不同的查询应该有不同的 return 类型。你说 conn.Query<ReturnType>(SQL) 的魔法线是你把手放在心上并承诺 SQL 将填充 ReturnType。如果在一个地方,ReturnType 包含查询永远不会填充的字段,那对我来说就是一种代码味道。维护该代码的人永远不会理解为什么会这样。如果稍后将来自不同查询的数据馈送到单个方法中,请创建一个接口。

ORM 思想的污染副作用是 "normalize" 您的 类 的愿望。如果他们在不同的情况下做不同的事情,那么拥有几十个 Person 对象并不一定是个问题。在您的数据库中,您不希望在两个地方有相同的数据。在您的应用程序中,您不希望在两个地方出现相同的行为。这些是非常不同的概念。如果你使用 QueryFirst(免责声明:我写的)这一切都会简单得多,你不必把手放在心上。

有一个选项可以使用 return 描述的动态类型 here 我更喜欢像 Tuple 这样的复合 return 类型,但是,它基本上是 Dapper 手册中描述的多映射。 (YMMV,我自己也是 Dapper 的新手)