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 的新手)
我有这个 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 的新手)