I'm trying to pass list of objects and some other numbers and strings parameters to a SQL Server stored procedure using ado.net and execute it, and retrieve a value from an output parameter.
To capture the list of objects from the SQL Server stored procedure, I used a user-defined table type as shown here:
And this is the stored procedure:
ALTER PROCEDURE [dbo].[UpdateMailjetDetails]
@listCode VARCHAR(1000),
@listName VARCHAR(1000),
@mailjetListId BIGINT,
@mailjetListStatus INT,
@autoAsync BIT,
@contacts Contact READONLY,
@companyId INT,
@tblContactCompanyStatus INT,
@espListContactStatus INT,
@outputMessage VARCHAR(1000) OUT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION [Tran1]
BEGIN TRY
-- logic
--
--
SET @outputMessage = 'success';
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION [Tran1];
SELECT
'Error - Rollbacked -' AS CustomMessage,
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
SET @outputMessage = 'error - ' + ERROR_MESSAGE();
END CATCH
END
This is the C# code which calls the stored procedure.
public string SaveAndPassToMailjetWindowsService(string listCode, string listName, long mailjetListId, MailjetListStatus mailjetListStatus, bool autoSync, List<Contact> contacts, int companyId, TblContactCompanyStatus tblContactCompanyStatus, EspListContactStatus espListContactStatus)
{
try
{
string result;
var conString = GetMailCoreConnectionString();
using (var conn = new SqlConnection(conString))
{
var command = new SqlCommand("UpdateMailjetDetails", conn)
{ CommandType = CommandType.StoredProcedure };
command.Parameters.Add(new SqlParameter("@listCode", listCode));
command.Parameters.Add(new SqlParameter("@listName", listName));
command.Parameters.Add(new SqlParameter("@mailjetListId", mailjetListId));
command.Parameters.Add(new SqlParameter("@mailjetListStatus", (int) mailjetListStatus));
command.Parameters.Add(new SqlParameter("@autoAsync", autoSync));
var contactsParam =
new SqlParameter("@contacts", SqlDbType.Structured)
{
TypeName = "dbo.Contact",
Value = GetSqlDataRecordsContactsList(contacts)
};
command.Parameters.Add(new SqlParameter("@contacts", contactsParam));
command.Parameters.Add(new SqlParameter("@companyId", companyId));
command.Parameters.Add(new SqlParameter("@tblContactCompanyStatus", (int) tblContactCompanyStatus));
command.Parameters.Add(new SqlParameter("@espListContactStatus", (int) espListContactStatus));
var outputParameter = new SqlParameter
{
ParameterName = "@outputMessage",
SqlDbType = SqlDbType.VarChar,
Direction = ParameterDirection.Output
};
command.Parameters.Add(outputParameter);
conn.Open();
command.ExecuteNonQuery(); // throws exception
result = outPutParameter.Value.ToString();
conn.Close();
}
return result;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
And below is the C# method which converts the contacts list to a data table.
private List<SqlDataRecord> GetSqlDataRecordsContactsList(List<Contact> contacts)
{
try
{
List<SqlDataRecord> datatable = new List<SqlDataRecord>();
SqlMetaData[] sqlMetaData = new SqlMetaData[5];
sqlMetaData[0] = new SqlMetaData("Email", SqlDbType.NVarChar, 512);
sqlMetaData[1] = new SqlMetaData("Name", SqlDbType.NVarChar, 512);
sqlMetaData[2] = new SqlMetaData("TblContactId", SqlDbType.BigInt);
sqlMetaData[3] = new SqlMetaData("CompanyId", SqlDbType.Int);
sqlMetaData[4] = new SqlMetaData("TblContactCompanyId", SqlDbType.BigInt);
foreach (var contact in contacts)
{
SqlDataRecord row = new SqlDataRecord(sqlMetaData);
row.SetValues(contact.Email, contact.Name, contact.TblContactId ?? (object) DBNull.Value,
contact.CompanyId ?? (object) DBNull.Value,
contact.TblContactCompanyId ?? (object) DBNull.Value);
datatable.Add(row);
}
return datatable;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
Now, when I run the code it does all the logic in stored procedure properly and completes all the changes I'm trying to do. I can see that data has been added via the stored procedure properly, but SaveAndPassToMailjetWindowsService
methods
command.ExecuteNonQuery();
throws an exception in the C# side (even though the stored procedure executed its logic properly).
No mapping exists from object type System.Data.SqlClient.SqlParameter to a known managed provider native type.
Any guidance to fix this is much appreciated. Thanks.
In order to use table-valued parameters we need to complete three steps: Create a User-Defined Table Type. Create the stored procedure where we are going to use the table-valued parameter and use the recently created User-Defined Table Type. Configure ADO.NET to send the parameter as a special parameter.
In order to fetch the multiple returned values from the Stored Procedure, you need to make use of a variable with data type and size same as the Output parameter and pass it as Output parameter using OUTPUT keyword. You can also make use of the Split function to split the comma separated (delimited) values into rows.
If you specify the output keyword for a parameter in the procedure definition, the procedure can return the current value of the parameter to the calling program when the procedure exits.
Here you are adding the parameter as a value for a parameter:
var contactsParam =
new SqlParameter("@contacts", SqlDbType.Structured)
{
TypeName = "dbo.Contact",
Value = GetSqlDataRecordsContactsList(contacts)
};
command.Parameters.Add(new SqlParameter("@contacts", contactsParam)); //Problem is here
It should just be:
command.Parameters.Add(contactsParam);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With