简单问题(已编辑:首先显示容易复制的示例,然后显示详细方案)
具有以下课程:
public class SalesMetrics {
public decimal SalesDollars { get; set; }
public decimal SalesUnits { get; set; }
}
public class ProductGroup {
public string ProductId { get; set; }
public string ProductName { get; set; }
}
使用以下Dapper查询,我的结果等于[{Key = null, Value = null}]
:
IEnumerable<KeyValuePair<ProductGroup, SalesMetrics>> result = sqlConnection
.Query<KeyValuePair<ProductGroup, SalesMetrics>>(
sql: @"SELECT
1 As ProductId,
'Test' AS ProductName,
1.00 As SalesDollars,
1 As SalesUnits");
我想知道Dapper是否可以将KeyValuePair作为输出类型处理,是这样的:查询的方式如何?
完整场景(为什么我需要这样做)
我正在创建一个“销售查询”构建器函数,该函数可以按不同的分组谓词对我的销售结果进行分组,并应基于该谓词type
返回不同的结果类型。
我正在使用Dapper
nuget包从SQL-Server
获取结果。我正在IDbConnection上使用Dapper.Query<T>()
扩展方法
基本上,无论分组类型如何,我都想返回sum
的SalesDollars和SalesUnits。对于输出的这一部分,我创建了以下类SalesMetrics
我希望我的Sales Query函数接受名为ProductGroup
的Group类(generic parameter
或任何其他类...)作为TGroup
,该函数应返回{ {1}}
数据源
这是我的销售表KeyValuePair<TGroup,SalesMetric>
FlatSales
我遇到问题的地方
我具有以下查询数据库的功能。
CREATE TABLE dbo.FlatSales (
SalesDate DATE NOT NULL,
ProductId INT NOT NULL,
ProductName VARCHAR(100) NOT NULL,
ProductCategoryId INT NOT NULL,
ProductCategoryName VARCHAR(100) NOT NULL,
CustomerGroupId INT NOT NULL,
CustomerGroupName VARCHAR(100) NOT NULL,
CustomerId INT NOT NULL,
CustomerName VARCHAR(100) NOT NULL,
SalesUnits INT NOT NULL,
SalesDollars INT NOT NULL
)
NULL的收集
代码public static IEnumerable<KeyValuePair<TGroup,SalesMetrics>> SalesTotalsCompute<TGroup>(System.Data.IDbConnection connection)
{
string[] groupByColumnNames = typeof(TGroup)
.GetProperties(bindingAttr: System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Select(x => x.Name)
.ToArray();
string joinedGroupByColumnsNames = string.Join(",", groupByColumnNames);
return connection.Query<KeyValuePair<TGroup, SalesMetrics>>(sql: $@"
SELECT SUM(SalesDollars) AS SalesDollars,
SUM(SalesUnits) AS SalesUnits,
{joinedGroupByColumnsNames}
FROM dbo.FlatSales
GROUP BY {joinedGroupByColumnsNames}
");
}
,但返回一个KeyValuePair列表,其中Key和Value均为does not fail
。
我尝试对NULL
之类的列进行别名设置,但是它并没有改变任何内容(也没有失败)...
为ProductName as [Key.ProductName]
生成的Sql查询如下(均返回空的KeyValuePair):
ProductGroup
有什么想法吗?
答案 0 :(得分:1)
我怀疑Dapper是否支持开箱即用的复杂对象。
也许您可以从Dapper的multi-mapping feature中受益:
NoMethodError: NoMethodError: undefined method `Beluga' for nil:NilClass
备注
AnimalVerifier
数组中的第一项,这会更加随机ValueTuple
,而不是public static IEnumerable<KeyValuePair<TGroup, SalesMetrics>> SalesTotalsCompute<TGroup>(System.Data.IDbConnection connection)
{
string joinedGroupByColumnsNames = string.Join(",", GetCachedColumnNamesFor<TGroup>());
return connection.Query<TGroup, SalesMetrics, KeyValuePair<TGroup, SalesMetrics>>(
sql: $@"SELECT {joinedGroupByColumnsNames},
SUM(SalesDollars) AS SalesDollars,
SUM(SalesUnits) AS SalesUnits
FROM dbo.FlatSales
GROUP BY {joinedGroupByColumnsNames}",
map: (groupData, salesMetricsData) => new KeyValuePair<TGroup, SalesMetrics>(groupData, salesMetricsData),
splitOn: "SalesDollars");
}
joinedGroupByColumnsNames
,该方法仅使用静态ConcurrentDictionary调用ConcurrentDictionary.GetOrAdd
方法,进行一次反射。其他方法
您还可以让KeyValuePair
从GetCachedColumnNamesFor
继承(或创建ProductGroup
接口并让SalesMetrics
实现该接口)并执行ISalesMetrics
。另一个好处是编译器将阻止两个模型中的重复字段。
生成的方法将如下所示:
ProductGroup
这里的Query<ProductGroup>(...)
方法反映了public static IEnumerable<TSalesData> SalesTotalsCompute<TSalesData>(System.Data.IDbConnection connection)
where TSalesData : ISalesMetric
{
string joinedGroupByColumnsNames = string.Join(",", GetCachedNonSalesMetricColumnNamesFor<TSalesData>());
return connection.Query<TSalesData>(sql: $@"
SELECT SUM(SalesDollars) AS SalesDollars,
SUM(SalesUnits) AS SalesUnits,
{joinedGroupByColumnsNames}
FROM dbo.FlatSales
GROUP BY {joinedGroupByColumnsNames}
");
}
中的属性,不包括GetCachedNonSalesMetricColumnNamesFor
接口中的属性,再次缓存了结果。