ADO.NET SqlCommand with TVP having nullable int column (I can build the parameter, but my reader ret

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
Hi. Ill try to make this quick: Im calling a stored procedure via an ADO.Net SqlCommand. The stored procedure requires a table valued parameter, and when I call command.ExecuteReader() the reader contains no rows. When I convert my logic to a SQL Script and execute directly in SSMS, I receive data.
The table type is defined similar to the following:CREATE TYPE [dbo].[BusinessTableType] AS TABLE(
[id] [int] NULL,
Code:
 [varchar](1000) NULL,
[ServiceType] [varchar](50) NULL,
[AccountNumber] [varchar](50) NULL
)
GO
The Sql script that returns looks something like the following:DECLARE @Accounts as dbo.BusinessTableType
insert into @Accounts(id,Code,ServiceType,AccountNumber)
select 3,Code,Service,1234567890

exec MyDatabase.MySchema.GetData @Accounts

I have mocked out a single row for testing.  This execution returns 66 rows.
...now, the offending code (only the relevant parts)var request= GetRequest(connection2);
var data = GetData(connection, connection2, request);

private RequestList GetRequest(SqlConnection connection)
{
//DataTable accounts = GetAccounts(connection);
DataTable accounts = GetAccountMock();
return GetRequest(connection, accounts);
}

private DataTable GetAccountMock()
{
DataTable mock = new DataTable("Accounts");

mock.Columns.Add("Id");
mock.Columns.Add("Code");
mock.Columns.Add("AccountNumber");
mock.Columns.Add("ServiceType");
mock.Rows.Add(  3
, "Code"
, "1234567890"
, "Service"
);
return mock;
}private AccountRequestList GetRequest(SqlConnection connection, DataTable accounts)
{
AccountRequestList request = new AccountRequestList();

foreach (DataRow row in accounts.Rows)
{
if ((row["Code"] != null && !row["Code"].Equals(String.Empty)) && (row["AccountNumber"] != null && !row["AccountNumber"].Equals(String.Empty)))
request.Add(new AccountRequest()
{
Code = row["Code"].ToString()
,AccountNumber = row["AccountNumber"].ToString()
,ServiceType = row["Service"].ToString()
,Id = string.IsNullOrEmpty(row["Id"].ToString()) ? (int?)null : Convert.ToInt32(row["Id"].ToString())
}
);
}
return request;
}

public class AccountRequestList: List<AccountRequest>, IEnumerable<SqlDataRecord>
{
IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
{
AccountRequestToSqlDataRecordConverter converter = new AccountRequestToSqlDataRecordConverter();
foreach (AccountRequest accountRequest in this)
{
yield return converter.Convert(accountRequest, typeof(SqlDataRecord), null, null) as SqlDataRecord;
}
}

}
public class AccountRequestToSqlDataRecordConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType() != typeof(AccountRequest)) return null;
if (targetType != typeof(SqlDataRecord)) return null;
AccountRequest request = value as AccountRequest;

SqlDataRecord record = new SqlDataRecord(
new SqlMetaData("Id",SqlDbType.Int),
new SqlMetaData("Code",SqlDbType.VarChar,-1),
new SqlMetaData("AccountNumber",SqlDbType.VarChar,-1),
new SqlMetaData("ServiceType",SqlDbType.VarChar,-1)

);
record.SetSqlInt32(0, request.Id.HasValue ? request.Id.Value : SqlInt32.Null); 
record.SetString(1, request.Code);
record.SetString(2, request.AccountNumber);
record.SetString(3, request.ServiceType);
return record;
}
}
private DataTable GetData(SqlConnection connection1, SqlConnection connection2, AccountRequestList request)
{
try
{
SqlDataReader reader;
int lastUsedId;
lastUsedId = GetLastUsedId(connection2);

SqlCommand command = new SqlCommand("[schema].[GetData]", connection1) { CommandType = CommandType.StoredProcedure };
if (connection1.State != ConnectionState.Open)
{
connection1.Open();
}
if (Dts.Variables["DatabaseTimeout"].Value is int)
{
command.CommandTimeout = (int)Dts.Variables["DatabaseTimeout"].Value;
}

SqlParameter minId = command.Parameters.AddWithValue("@MinId", lastUsedId);
minUsage.SqlDbType = SqlDbType.Int;

SqlParameter maxId = command.Parameters.AddWithValue("@MaxUsedId", Int32.MaxValue);
maxUsage.SqlDbType = SqlDbType.Int;

SqlParameter AccountRequest = command.Parameters.AddWithValue("@StoredProcParameterName", request);
AccountRequest.SqlDbType = SqlDbType.Structured;
AccountRequest.TypeName = "dbo.BusinessTableType";

reader = command.ExecuteReader();

while (reader.Read())//has no records

My thought is that it has something to do with the SqlMetaData on the "Id" field that I am using in my Converter, but thats just a guess at this point.  Im still actively trying to figure this out for myself, but I wanted to spin up this post in case someone more experienced with passing Table Valued Parameters inside a SqlCommand sees something obvious that I just am not seeing.

[url=http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/cc0c5d65-3bea-418b-b3b0-6cf35eea488f]View the full article[/url]
 
Back
Top