简体   繁体   中英

Passing a List of objects to SQL Server stored procedure and retrieving an output value

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.

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM