C# 当源是DataReader时,如何指定在表值参数中使用服务器定义的值?
我的TVP看起来像这样:C# 当源是DataReader时,如何指定在表值参数中使用服务器定义的值?,c#,sql-server,.net-core,sqldatareader,table-valued-parameters,C#,Sql Server,.net Core,Sqldatareader,Table Valued Parameters,我的TVP看起来像这样: 创建类型p_tvp为表 ( id int标识不为空, 值浮动不为空 ) 我有一些datareader,它会生成一个double列表(不是实际执行的SQL): 使用(var conn=new SqlConnection(\u srcString) 使用(var cmd=new SqlCommand(“从(值(1e)、(2e)、(3e))f(v)中选择*,conn)) { 等待连接OpenAsync(); 使用(var rdr=await _cmd.ExecuteRead
创建类型p_tvp为表
(
id int标识不为空,
值浮动不为空
)
我有一些datareader,它会生成一个double列表(不是实际执行的SQL):
使用(var conn=new SqlConnection(\u srcString)
使用(var cmd=new SqlCommand(“从(值(1e)、(2e)、(3e))f(v)中选择*,conn))
{
等待连接OpenAsync();
使用(var rdr=await _cmd.ExecuteReaderAsync())
使用(var tCon=new SqlConnection(_targetString))
使用(var tcmd=newsqlcommand(“MyStoredProcedure”,tCon))
{
等待tCon.OpenAsync();
tcmd.CommandType=CommandType.StoreProcedure;
var param=tcmd.Parameters.AddWithValue(@tvp,rdr);
param.SqlDbType=SqlDbType.Structured;
param.TypeName=“dbo.p_tpv”;
等待tcmd.ExecuteNonQuery();
}
}
我得到的错误是我没有足够的参数。因为我的目标TVP有2列。如果我添加一个伪列,我得到的错误是我无法将标识插入到表值参数中
我无法重新定义TVP
另一个问题指定一个
DataTable
作为源,答案使用IEnumerable
。不幸的是,这两个问题都不能解决我使用DbDataReader
的问题。如果需要,我可以转换为SqlDataRecord
,但我想避免额外的步骤,因为我无法轻松控制DbDataReader
source.正如法比奥在对该问题的评论中所指出的,您可以使用IEnumerable
通过SqlDataRecord
设置自定义数据结构,然后将结果从SqlDataReader
流式传输到TVP中
在下面的示例中,TVP的“id”列使用了SqlMetaData
构造函数,该构造函数允许将useServerDefault
设置为true
。如果原始查询中没有返回任何行,产量中断应该安全退出
private IEnumerable SendRowsToProc(SqlDataReader)
{
如果(!reader.HasRows)
{
屈服断裂;
}
SqlDataRecord resultRow=新的SqlDataRecord(新的SqlMetaData[]{
新的SqlMetaData(“id”,SqlDbType.Int,true,true,SortOrder.Unspecified,0),
新的SqlMetaData(“值”,SqlDbType.Float)
});
while(reader.Read())
{
resultRow.SetDouble(1,reader.GetDouble(0));
收益率收益率;
}
}
因此,不是将rdr作为TVPSqlParameter
的“值”传入,而是传入:SendRowsToProc(rdr)
另一个选项,如果您真的想通过<代码> RDR < /C> >作为TVP值:
使用不同的UDTT,该UDTT具有相同的ID INT NOT NULL
列,但未标记为标识
在选择语句(在源代码处)中,以以下内容开始列列表:
ROW_NUMBER() OVER (ORDER BY @@MICROSOFTVERSION) AS [ID]
这应该提供与IDENTITY
列当前提供的功能相同的功能。当然,如果您正在执行存储过程,它将不起作用,但对于问题中给出的情况,它应该可以正常工作。正如Fabio在对问题的评论中指出的,您可以使用IEnumerable
来设置自定义数据结构通过SqlDataRecord
执行CTU,然后将结果从SqlDataReader
流式传输到TVP
在下面的示例中,TVP的“id”列使用了SqlMetaData
构造函数,该构造函数允许将useServerDefault
设置为true
。如果原始查询中没有返回任何行,产量中断应该安全退出
private IEnumerable SendRowsToProc(SqlDataReader)
{
如果(!reader.HasRows)
{
屈服断裂;
}
SqlDataRecord resultRow=新的SqlDataRecord(新的SqlMetaData[]{
新的SqlMetaData(“id”,SqlDbType.Int,true,true,SortOrder.Unspecified,0),
新的SqlMetaData(“值”,SqlDbType.Float)
});
while(reader.Read())
{
resultRow.SetDouble(1,reader.GetDouble(0));
收益率收益率;
}
}
因此,不是将rdr作为TVPSqlParameter
的“值”传入,而是传入:SendRowsToProc(rdr)
另一个选项,如果您真的想通过<代码> RDR < /C> >作为TVP值:
使用不同的UDTT,该UDTT具有相同的ID INT NOT NULL
列,但未标记为标识
在选择语句(在源代码处)中,以以下内容开始列列表:
ROW_NUMBER() OVER (ORDER BY @@MICROSOFTVERSION) AS [ID]
这应该提供与IDENTITY
列当前提供的功能相同的功能。当然,如果您正在执行存储过程,它将不起作用,但对于问题中给出的情况,它应该可以。不过,您也可以使用读卡器来启用流。如果您使用数据表,则必须具体化数据我的实际源数据库不是Sql Server。是的,我这样做了。这又不是我的实际代码,但我会更新我的示例。这可能再次重复,这是一个数据表(实际答案通过IEnumerable
实现。我有一个DbDataReader
。你不能用DbDataReader来做这件事,你可以用“流”来实现DbDataReader进入IEnumerable
。使用IEnumerable
您将一次枚举一行,而不会将整个数据具体化。您也可以使用reader来启用流式处理。如果您使用datatable,则必须具体化数据集。我的实际源数据库不是Sql Server。是的,我这样做。这又不是我的actu所有代码,但我将更新我的示例。可能的重复,这是针对datatable(实际答案实现)