我正在使用QueryMultiple
执行存储过程以返回多组数据。
var gridReader = db.QueryMultiple("sp",
parameters,
commandType: CommandType.StoredProcedure);
我知道他们将重新进入的顺序,我可以非常轻松地获得每一套。
SELECT * FROM dbo.Set1;
SELECT * FROM dbo.Set2;
SELECT * FROM dbo.Set3;
var set1 = gridReader.Read<Set1>();
var set2 = gridReader.Read<Set2>();
var set3 = gridReader.Read<Set3>();
但是,我处于这样一种情况,即他们将要回来的订单可能会改变。另一位开发人员可以出于任何原因决定更改订单。存储过程现在变为:
SELECT * FROM dbo.Set1;
SELECT * FROM dbo.Set3;
SELECT * FROM dbo.Set2;
我该如何处理?
我最初的尝试是迭代每个网格,检查列名称。这看起来效果很好,但除了手动设置每个字段之外,我无法弄清楚如何将网格投影到类中。我使用Dapper的主要原因是它可以为我做到这一点。
while (true)
{
var grid = gridReader.Read();
IDictionary<string, object> row = grid.FirstOrDefault();
if (row == null)
break;
if (row.Keys.Contains("Set1_UniqueColumnName"))
{
// Need something like grid.Read<Set1>();
}
else if (row.Keys.Contains("Set2_UniqueColumnName")) { }
else if (row.Keys.Contains("Set3_UniqueColumnName")) { }
}
我的第二个想法是将每个网格读入一个类,检查类的唯一字段是否为空值/默认值,如果测试失败则尝试下一个类。这显然不会起作用。 .Read()
将返回 next 结果网格。这个解决方案要求我能够一遍又一遍地读取相同的网格。
答案 0 :(得分:2)
Dapper提供IDataReader.GetRowParser
扩展方法,允许每行进行类型切换。来自Dapper docs here ...
通常,您希望将给定表中的所有行视为相同 数据类型。但是,在某些情况下,它有用 能够将不同的行解析为不同的数据类型。这是哪里 IDataReader.GetRowParser派上用场。
想象一下,您有一个名为“Shapes”的数据库表,其中包含以下列:Id, 键入和数据,并且要将其行解析为Circle,Square或 三角形对象基于Type列的值。
var shapes = new List<IShape>();
using (var reader = connection.ExecuteReader("select * from Shapes"))
{
// Generate a row parser for each type you expect.
// The generic type <IShape> is what the parser will return.
// The argument (typeof(*)) is the concrete type to parse.
var circleParser = reader.GetRowParser<IShape>(typeof(Circle));
var squareParser = reader.GetRowParser<IShape>(typeof(Square));
var triangleParser = reader.GetRowParser<IShape>(typeof(Triangle));
var typeColumnIndex = reader.GetOrdinal("Type");
while (reader.Read())
{
IShape shape;
var type = (ShapeType)reader.GetInt32(typeColumnIndex);
switch (type)
{
case ShapeType.Circle:
shape = circleParser(reader);
break;
case ShapeType.Square:
shape = squareParser(reader);
break;
case ShapeType.Triangle:
shape = triangleParser(reader);
break;
default:
throw new NotImplementedException();
}
shapes.Add(shape);
}
}
您需要访问IDataReader
包装或更改代码的GridReader
,以使用老式的ADO.NET SqlConnection
&amp; SqlCommand
这样的对象......
using (command = new SqlCommand("sp", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(parameters);
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
// read row columns
}
}
}
答案 1 :(得分:1)
Davmos's answer指出了我正确的方向。需要使用ADO.NET和Dapper的组合。本质上使用ADO.NET来检索和迭代数据,但使用Dapper将行解析为我的对象。注意在while循环中使用FieldCount
,以防结果集实际返回0行。我们希望它继续下一个结果集,而不是摆脱循环。
Set1 set1 = null;
var set2 = new List<Set2>();
Set3 set3 = null;
using (var command = new SqlCommand("sp", conn))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddRange(parameters);
command.Connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.FieldCount > 0)
{
var set1Parser = reader.GetRowParser<Set1>();
var set2Parser = reader.GetRowParser<Set2>();
var set3Parser = reader.GetRowParser<Set3>();
var isSet1 = HasColumn(reader, "Set1_UniqueColumnName");
var isSet2 = HasColumn(reader, "Set2_UniqueColumnName");
var isSet3 = HasColumn(reader, "Set3_UniqueColumnName");
while (reader.Read())
{
if (isSet1)
{
set1 = set1Parser(reader);
}
else if (isSet2)
{
set2.Add(set2Parser(reader));
}
else if (isSet3)
{
set3 = set3Parser(reader);
}
}
reader.NextResult();
}
}
}
public static bool HasColumn(IDataReader reader, string columnName)
{
for (var i = 0; i < reader.FieldCount; i++)
{
if (reader.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}
return false;
}