在.NET环境中,处理存储过程返回的数据时,开发者通常需要预先定义一个类来映射存储过程返回的每一列的字段名和数据类型。然而,随着业务需求的多样化,存储过程可能需要支持行转列的透视操作或者动态执行SQL语句,这就要求能够处理动态字段。最近,为了满足这种需求,更新了存储过程框架,以支持动态字段。
例如,考虑以下基本的存储过程:
CREATE PROCEDURE [app].[GetPossibleDynamicStoredProcedure]
AS
BEGIN
SELECT
'Dave' AS [Firstname],
'Smith' AS [Surname],
32 AS [Age],
GETDATE() AS [DateOfBirth]
UNION
SELECT
'Peter' AS [Firstname],
'Pan' AS [Surname],
134 AS [Age],
GETDATE() AS [DateOfBirth];
END
在更新之前,需要一个类来定义每个字段,这限制了调用具有动态字段名或数据类型的存储过程的能力。
在.NET中,可以通过定义一个类来表示存储过程返回的行,例如:
[Schema("app")]
internal class GetPossibleDynamicStoredProcedure
: NoParametersStoredProcedureBase>
{
internal class Return
{
public string Firstname { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
public DateTime DateOfBirth { get; set; }
}
}
但现在,存储过程框架已经更新,以支持使用.NET的ExpandoObject作为返回类型列表的类型参数,从而支持动态字段。
[Schema("app")]
internal class GetDynamicColumnStoredProcedure
: NoParametersStoredProcedureBase> { }
存储过程框架将返回一个ExpandoObjects的列表,然后可以根据需要将其转换为.NET的dynamic对象。以下是一个单元测试的示例:
[TestClass]
public class DynamicColumnStoredProcedure
: SqlConnectionExampleTestBase
{
[TestMethod]
public void GetDynamicColumnStoredProcedure()
{
// ARRANGE
var procedure = new GetDynamicColumnStoredProcedure();
// ACT
var results = Connection.ExecuteStoredProcedure(procedure);
var result = results.First();
// ASSERT
Assert.IsTrue(DynamicObjectHelper.HasProperty(result, "Firstname"));
Assert.IsTrue(DynamicObjectHelper.HasProperty(result, "Surname"));
Assert.IsTrue(DynamicObjectHelper.HasProperty(result, "Age"));
Assert.IsTrue(DynamicObjectHelper.HasProperty(result, "DateOfBirth"));
Assert.IsFalse(DynamicObjectHelper.HasProperty(result, "MiddleName"));
var dynamicResult = (dynamic)result;
Assert.AreEqual("Dave", dynamicResult.Firstname);
Assert.AreEqual("Smith", dynamicResult.Surname);
Assert.AreEqual(32, dynamicResult.Age);
}
}
需要注意的是,目前动态字段在存储过程中只支持单记录集。支持具有动态列的多个记录集的功能正在开发中。