2017-02-08 68 views
1

我用短小精悍(在现实中我使用一个真正的表)这工作样品查询:Dapper可以返回映射对象和其他非映射值吗?

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

结果:

enter image description here

所以映射工作正常。但有时我必须返回像另一个值查询:

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

这是完全合法的:

enter image description here

问:

是否有可能返回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] 

所以我返回Address对象与关于同一个表计数和我不想要另一个选择。

回答

1

最简单的事情就是将cnt添加到Person类中。你当然可以将它重命名为更有意义的东西。将它设置为一个可为空的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并不真正属于人的班级,但通常你不会一个数据集分配给这样的类,你将它分配给像一个DTO,然后映射到这一点无论模型类或您拥有的课程,并以您认为合适的方式使用额外的属性。这将使您的业务类(如Person)保持纯粹。

+0

MMM ...有道理。所以我可以创建一个名为'PersonCounted'的派生Person类型,它将具有这个额外的道具。 –

+0

当然,只需更改sql代码中的名称“cnt as PersonCount”,它就可以完成这项工作,或者只是PersonCount = whateevr –

1

是的,您可以使用QueryMultiple扩展名。但是,你应该使用单独的选择为获得列数:

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一部分。

另一种返回附加值的方法是动态查询。但在这种情况下,你必须手动建立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; 

AFAIK有没有其他办法返回的人都和CNT。

+0

我知道。但正如我所提到的(_(在同一选择中)_) - 没有两次击中表的要点。有时候我会在分区和其他窗口函数上添加rownumber,所以我需要它在同一个select中 –

+0

@RoyiNamir你没有碰到第一个选择的表 –

+0

这只是一个例子(为简单起见)。实际上,我从表(及其列)中选择并返回另一个窗口函数('sum over(order by ...)') –

1

您确定要这么做吗?正如歌曲所说,保持生活的阳光一面。A查询应该有a返回类型。不同的查询应该有不同的返回类型。您所说的conn.Query<ReturnType>(SQL)的神奇之处在于您将自己的手放在心上,并承诺SQL将填充ReturnType。如果在一个地方,ReturnType具有查询从不打算填充的字段,那对我来说是一种代码异味。有人维护该代码将永远不会明白为什么它是这样的。如果将来自不同查询的数据稍后输入到单一方法中,请创建一个接口。

ORM思维的污染副作用是希望“规范化”你的课程。拥有数十个Person对象不一定是一个问题,如果他们在不同的情况下做不同的事情。在你的数据库中,你不需要在两个地方使用相同的数据。在你的应用程序中,你不需要在两个地方使用相同的行为。这些是非常不同的概念。如果您使用的是QueryFirst(免责声明:我写的),这样做会简单得多,而且您不必把手放在心上。

+0

谢谢 - 基本上你说'conn.Query (SQL)'是一个可行的解决方案。对 ? –

+0

基本上,这就是我说的! – bbsimonbb

0

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