ASP.NET存储过程调用将VarBinary插入到sql中

时间:2018-05-04 14:11:24

标签: ios sql asp.net asp.net-mvc stored-procedures

我有一个字符串,它是来自iOS的数据字节base64EncodedString,这是一个非常长的字符串

let imageStr = imageData.base64EncodedString()

我从我的ios调用.NET方法,它将调用存储过程将这些字节插入数据库。

这是我的.NET方法,我将数据类型设置为VarBinary

public string PostLandGradingImages(List<Images> landingCells)
{
    try
    {
        using (connection = new SqlConnection(connectionString))
        {
            connection.Open();

            using (SqlCommand command = new SqlCommand("PostLandGradingImages", connection))
            {
                command.CommandType = CommandType.StoredProcedure;

                for (int i = 0; i < landingCells.Count; i++)
                {
                    command.Parameters.Clear();

                    SqlParameter parameter1 = new SqlParameter("@Job_No", SqlDbType.VarChar);
                    parameter1.Value = landingCells[i].jobNo;
                    parameter1.Direction = ParameterDirection.Input;
                    command.Parameters.Add(parameter1);

                    SqlParameter parameter2 = new SqlParameter("@Image", SqlDbType.VarBinary);
                    parameter2.Value = landingCells[i].imageBytes;
                    parameter2.Direction = ParameterDirection.Input;
                    command.Parameters.Add(parameter2);

                    command.ExecuteNonQuery();
                }
            }
        }
    }
    catch (Exception e)
    {
        return e.Message.ToString();
    }

    return "All Good";
}

这是我的Image Class,请注意我的imageBytes被定义为byte []:

public class Images
{
    public string jobNo { get; set; }
    public byte[] imageBytes { get; set; }
}

我插入的列定义为varbinary(MAX)

这是我的存储过程:

ALTER PROCEDURE [dbo].[PostLandGradingImages] 
    -- Add the parameters for the stored procedure here
    @Job_No varchar(MAX) = NULL,
    @Image varbinary(MAX) = NULL
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    INSERT INTO LandGradingImages (Job_No, ImageBytes) VALUES (@Job_No, @Image)
END

我的问题是什么都没有插入,我收到了这个错误:

  

对象引用未设置为对象的实例。

我的问题是,我做错了什么?我不应该发送base64EncodedString或者我没有设置我的课程吗?还是我的db列?

我试过了:

byte[] bytes = System.Convert.FromBase64String(landingCells[i].imageBytes);

SqlParameter parameter2 = new SqlParameter("@Image", SqlDbType.VarBinary, 800000);
parameter2.Value = bytes;
parameter2.Direction = ParameterDirection.Input;
command.Parameters.Add(parameter2);

仍然无效:(我将imageBytes更改为字符串。

2 个答案:

答案 0 :(得分:3)

我将您的代码稍微修改为以下方法。它会为每个CommandType.StoredProcedure创建一个新的Image。每个图像也会返回结果,因此您可以看到哪些图像失败了。在你的方法中,如果你有10张图片,而第9张图片失败了,你就不会知道。

public List<Images> PostLandGradingImages(List<Images> landingCells)
{
    //create a connection to the database
    using (SqlConnection connection = new SqlConnection(Common.connectionString))
    {
        //loop all the images
        for (int i = 0; i < landingCells.Count; i++)
        {
            //create a fresh sql command for every Image
            using (SqlCommand command = new SqlCommand("PostLandGradingImages", connection))
            {
                command.CommandType = CommandType.StoredProcedure;

                //add the parameters
                command.Parameters.Add("@Job_No", SqlDbType.VarChar).Value = landingCells[i].jobNo;
                command.Parameters.Add("@Image", SqlDbType.VarBinary).Value = landingCells[i].imageBytes;

                try
                {
                    //open the connection if closed
                    if (connection.State == ConnectionState.Closed)
                    {
                        connection.Open();
                    }

                    //execute the stored procedure
                    command.ExecuteNonQuery();

                    //set the save result to the image
                    landingCells[i].saveResult = true;
                }
                catch (Exception ex)
                {
                    //handle error per Image
                    landingCells[i].errorMessage = ex.Message;
                }
            }
        }
    }

    return landingCells;
}

为了跟踪每个图像的保存结果,我已经为Image类添加了两个属性,但这也可以通过其他各种方式完成。

public class Images
{
    public string jobNo { get; set; }
    public byte[] imageBytes { get; set; }

    public bool saveResult { get; set; }
    public string errorMessage { get; set; }
}

使用以下代码完成了一个简单的测试。他们都没有给出NullReference错误。即使两个属性都是null,仍然会创建数据库条目。

//create a new list with Images
List<Images> landingCells = new List<Images>();

//add some dummy data
landingCells.Add(new Images() { jobNo = null, imageBytes = null });
landingCells.Add(new Images() { jobNo = "Job 1", imageBytes = null });
landingCells.Add(new Images() { jobNo = null, imageBytes = new byte[10000] });
landingCells.Add(new Images() { jobNo = "Job 2", imageBytes = new byte[10000] });

//send the images to be saved
landingCells = PostLandGradingImages(landingCells);

//loop all the images to check the result
for (int i = 0; i < landingCells.Count; i++)
{
    if (landingCells[i].saveResult == false)
    {
        //display the result for each failed image
        Label1.Text += landingCells[i].errorMessage + "<br>";
    }
}

如果仍然存在NullReference错误,则表示您的List landingCells本身为null,或者该List中的Image对象为null(在这种情况下,它应该永远不会被添加到List中)放置imho)。您可以轻松更改代码段以进行检查。

答案 1 :(得分:0)

考虑在事务中批处理查询。此外,您应验证提供给方法的值,以确保您可以正确调用存储过程。

public int PostLandGradingImages(List<Images> landingCells) {
    int count = 0;
    using (var connection = new SqlConnection(connectionString)) {
        connection.Open();
        //Transaction to batch the actions.
        using (var transaction = connection.BeginTransaction()) {
            foreach (var image in landingCells) {
                if (valid(image)) {//validate input properties.
                    try {
                        using (SqlCommand command = connection.CreateCommand()) {
                            command.CommandType = CommandType.StoredProcedure;
                            command.CommandText = "PostLandGradingImages";
                            command.Parameters
                                .Add("@Job_No", SqlDbType.VarChar, image.jobNo.Length)
                                .Value = image.jobNo;
                            command.Parameters
                                .Add("@Image", SqlDbType.VarBinary, image.imageBytes.Length)
                                .Value = image.imageBytes;
                            count += command.ExecuteNonQuery();
                        }
                    } catch {
                        //TODO: Log error
                    }
                }
            }
            if (landingCells.Count == count) {
                transaction.Commit();
            }
        }
    }
    return count;
}

private bool valid(Images image) {
    return image != null && String.IsNullOrWhiteSpace(image.jobNo)
        && image.imageBytes != null && image.imageBytes.Length > 0;
}