Как отметил Фабио в комментарии к вопросу, вы можете использовать IEnumerable<SqlDataRecord>
, чтобы настроить пользовательскую структуру данных с помощью SqlDataRecord
, а затем передать результаты из SqlDataReader
в TVP.
В следующем примере в столбце «id» TVP используется конструктор SqlMetaData
, который позволяет установить useServerDefault
в true
. yield break
должен безопасно завершиться, если в исходном запросе не было возвращено ни одной строки.
private IEnumerable<SqlDataRecord> SendRowsToProc(SqlDataReader reader)
{
if (!reader.HasRows)
{
yield break;
}
SqlDataRecord resultRow = new SqlDataRecord(new SqlMetaData[] {
new SqlMetaData("id", SqlDbType.Int, true, true, SortOrder.Unspecified, 0),
new SqlMetaData("value", SqlDbType.Float)
});
while (reader.Read())
{
resultRow.SetDouble(1, reader.GetDouble(0));
yield return resultRow;
}
}
Итак, вместо того, чтобы передавать rdr
в качестве «значения» TVP SqlParameter
, вы передаете: SendRowsToProc(rdr)
.
Другой вариант для рассмотрения, если вы действительно хотите передать rdr
в качестве значения TVP:
- Используйте другой UDTT, который имеет тот же столбец
ID INT NOT NULL
, но это , а не , помеченный как IDENTITY
В вашем операторе SELECT
(у источника) начните список столбцов с:
ROW_NUMBER() OVER (ORDER BY @@MICROSOFTVERSION) AS [ID]
Это должно обеспечить те же функции, что и столбец IDENTITY
в настоящее время. Конечно, это не будет работать, если вы выполняете хранимую процедуру, но для случая, указанного в вопросе, это должно быть хорошо.