【问题标题】:setting the default value null for sql parameters为sql参数设置默认值null
【发布时间】:2013-04-28 12:44:10
【问题描述】:

单击vb中的添加按钮后,如果您不将文本框字段留空或为空,则代码执行良好

但是当将某些字段留空时,它会返回错误

将参数值从 String 转换为 Int32 失败

存储过程

CREATE PROCEDURE AddOfficeEquipmentProfile
(
@OE_ID      varchar(11),    
@OE_Category        char(3) =NULL,      
@OE_SubCategory char(3)=    NULL,       
@OE_Name        varchar(35)=NULL,       
@OE_User        varchar(35)=NULL,   
@OE_Brand       varchar(15)=NULL,   
@OE_Model       varchar(35)=NULL,   
@OE_Specs       varchar(1000)=NULL,     
@OE_SerialNo        varchar(35)=NULL,   
@OE_PropertyNo  varchar(35)=NULL,   
@OE_MacAddress  varchar(100)=NULL,      
@OE_Static_IP       varchar(15)=NULL,   
@OE_Vendor      varchar(35)=NULL,   
@OE_PurchaseDate    smalldatetime,      
@OE_WarrantyInclusiveYear   int=NULL,   
@OE_WarrantyStatus  char(2)=    NULL,   
@OE_Status      varchar(15)=NULL,       
@OE_Dept_Code   char(3)=    NULL,   
@OE_Location_Code   char(8)=    NULL,       
@OE_Remarks     varchar(1000)=  NULL
)
AS

INSERT INTO tblOfficeEquipmentProfile (OE_ID, OE_Category, OE_SubCategory, OE_Name, OE_User, OE_Brand, OE_Model, OE_Specs, OE_SerialNo,
OE_PropertyNo, OE_MacAddress, OE_Static_IP, OE_Vendor, OE_PurchaseDate, OE_WarrantyInclusiveYear, OE_WarrantyStatus, OE_Status, OE_Dept_Code,
OE_Location_Code, OE_Remarks ) 
VALUES (@OE_ID, @OE_Category, @OE_SubCategory, @OE_Name, @OE_User, @OE_Brand, @OE_Model, 
@OE_Specs, @OE_SerialNo, @OE_PropertyNo, @OE_MacAddress, @OE_Static_IP, @OE_Vendor, @OE_PurchaseDate, @OE_WarrantyInclusiveYear, @OE_WarrantyStatus,
@OE_Status, @OE_Dept_Code, @OE_Location_Code, @OE_Remarks)

GO

VB.NET 代码

        cmd.CommandType = CommandType.StoredProcedure
        cmd.CommandText = "AddOfficeEquipmentProfile"

    cmd.Parameters.Add("@OE_ID", SqlDbType.VarChar, 11, "oeq-su-999")
    cmd.Parameters.Add("@OE_Category", SqlDbType.Char, 3, "COM").Value = DBNull.Value
    cmd.Parameters.Add("@OE_SubCategory", SqlDbType.Char, 3, "SU").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Name", SqlDbType.VarChar, 35, "adminpmis01").Value = DBNull.Value
    cmd.Parameters.Add("@OE_User", SqlDbType.VarChar, 35, "Ivan").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Brand", SqlDbType.VarChar, 15, "DELL").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Model", SqlDbType.VarChar, 35, "optiplex").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Specs", SqlDbType.VarChar, 1000, "dualcore").Value = DBNull.Value
    cmd.Parameters.Add("@OE_SerialNo", SqlDbType.VarChar, 35, "sgh5960").Value = DBNull.Value
    cmd.Parameters.Add("@OE_PropertyNo", SqlDbType.VarChar, 35, "j7h7h6g6f2").Value = DBNull.Value
    cmd.Parameters.Add("@OE_MacAddress", SqlDbType.VarChar, 100, "j7h7:h6g6f2").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Static_IP", SqlDbType.VarChar, 15, "192.168.1.5").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Vendor", SqlDbType.VarChar, 35, "ADWAYS").Value = DBNull.Value
    cmd.Parameters.Add("@OE_PurchaseDate", SqlDbType.DateTime)
    cmd.Parameters.Add("@OE_WarrantyInclusiveYear", SqlDbType.Int).Value = DBNull.Value
    cmd.Parameters.Add("@OE_WarrantyStatus", SqlDbType.Char, 2, "IN").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Status", SqlDbType.VarChar, 15, "Good").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Dept_Code", SqlDbType.Char, 3, "ADM").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Location_Code", SqlDbType.Char, 8, "ADM_OFC").Value = DBNull.Value
    cmd.Parameters.Add("@OE_Remarks", SqlDbType.VarChar, 1000, "ACTIVE").Value = DBNull.Value

    cmd.Parameters("@OE_ID").Value = txtOEID.Text
    cmd.Parameters("@OE_Category").Value = cmbCategory.Text
    cmd.Parameters("@OE_SubCategory").Value = cmbSubCategory.Text
    cmd.Parameters("@OE_Name").Value = txtName.Text
    cmd.Parameters("@OE_User").Value = txtUser.Text
    cmd.Parameters("@OE_Brand").Value = cmbBrand.Text
    cmd.Parameters("@OE_Model").Value = cmbModel.Text
    cmd.Parameters("@OE_Specs").Value = txtSpecs.Text
    cmd.Parameters("@OE_SerialNo").Value = txtSerialNo.Text
    cmd.Parameters("@OE_PropertyNo").Value = txtPropertyNo.Text
    cmd.Parameters("@OE_MacAddress").Value = txtMacAddress.Text
    cmd.Parameters("@OE_Static_IP").Value = txtStaticIP.Text
    cmd.Parameters("@OE_Vendor").Value = txtVendor.Text
    cmd.Parameters("@OE_PurchaseDate").Value = dtpPurchaseDate.Value
    cmd.Parameters("@OE_WarrantyInclusiveYear").Value = txtWarrantyInclusiveYear.Text
    cmd.Parameters("@OE_WarrantyStatus").Value = txtWarrantyStatus.Text
    cmd.Parameters("@OE_Status").Value = txtStatus.Text
    cmd.Parameters("@OE_Dept_Code").Value = cmbDeptCode.Text
    cmd.Parameters("@OE_Location_Code").Value = cmbLocationCode.Text
    cmd.Parameters("@OE_Remarks").Value = txtRemarks.Text
    cmd.ExecuteNonQuery()
    sqlconn.Close()

【问题讨论】:

    标签: sql vb.net


    【解决方案1】:

    我认为您缺少什么(因为您在过去几天中多次就这个问题提出了一个变体)是对表单中的控件如何映射到与您的 @987654321 关联的参数的理解@, 以及这些SqlCommand 参数如何映射到存储过程的参数。缺乏理解(因为你正在学习,缺乏并不是一件坏事)加上如何处理 NULL 值导致你悲伤没有尽头。

    我将尝试解释整个概念,而不是给您一个问题的单一答案,以便您可以将其应用于您在编写代码时可能遇到的任何情况。

    首先,您的表单上有一组TextBoxComboBox 控件。这两个控件都有一个Text 属性 - 该属性always 返回一个字符串,即使您在其中输入了 12345 或 10/01/2007。这意味着您必须将您从 TextBox.TextComboBox.Text 获得的字符串强制转换(转换)为相关存储过程参数的适当数据类型(除非其 CHAR/VARCHAR 或类似的东西)。

    当您创建 SqlCommand 对象时,您正在向参数集合添加参数。顺便说一句,这是一个非常好的做法,感谢您学习它 - 因为它可以减轻 SQL 注入攻击(在 WinForm 应用程序中并不总是高风险,但它是一种很好的编码做法进入。

    您添加到SqlCommandSqlParameter 对象需要匹配存储过程中的参数,您也这样做,这很好。但是,您可能正在尝试在第四个参数中传递默认值,而该参数不是用于设置默认值,而是用于在 UPDATE 语句中指定源列。

    你终于有了你的存储过程。不需要任何参数 - 因此您可以安全地接受任何在表单中没有值的参数。本质上,当您在存储过程中为参数设置默认值(NULL 或其他任何值)时,您可以在调用中省略该参数,SQL Server 将使用您在存储过程声明中指定的默认值。

    您正在按原样在代码中做额外的工作 - 首先将参数全部设置为 null,然后通过将值设置为等于表单上相应控件的值来覆盖该分配。这是您遇到最多麻烦的地方。

    正如其他人至少对您的几个问题所建议的那样,我会检查控件是否有值 - 如果有,则将参数及其值添加到集合中(根据需要进行转换)。这将减少您的“双重”分配。

    所以它看起来像这样:

    If txtOEID.Text.Trim() <> "" Then
        cmd.Parameters.Add("@OE_ID", SqlDbType.VarChar, 11).Value = txtOEID.Text.Trim()
    End If
    If cmbCategory.Text.Trim() <> "" Then
        cmd.Parameters.Add("@OE_Category", SqlDbType.Char, 3).Value = cmbCategory.Text.Trim()
    End If
    

    等等。当你有一个非 VARCHAR/CHAR 参数时,你需要做一些额外的工作(因为你使用 DateTimePicker 作为购买日期,Value 属性已经是 DateTime 所以你不要'不用担心):

    If IsNumeric(txtWarrantyInclusiveYear.Text) Then
        cmd.Parameters.Add("@OE_WarrantyInclusiveYear", SqlDbType.Int).Value = Integer.Parse(txtWarrantyInclusiveYear.Text)
    End If
    

    在上述情况下,我建议使用 IsNumeric 来增加您不会意外尝试解析非数字值的机会(因为您使用的是 VS 2003/.NET 1.1 TryParse 不可用)。

    简而言之,当您在应用程序中创建参数时,您需要了解从用户传入的数据类型,以及存储过程所期望的数据类型。如果它们不匹配,则需要在将参数添加到集合时将用户输入转换为存储过程的正确数据类型。

    如果参数在存储过程中指定了默认值,那么如果用户没有提供值,您可以直接跳过添加参数。尽管在 NULL 的情况下,请确保您插入的目标列被标记为 NULLABLE。

    我强烈建议您放弃 VS 2003 并使用 VS 2012 的 Express 版本,因为您错过了一大堆功能,这些功能将使您作为程序员的生活更轻松。

    如果您需要澄清任何事情,请询问。

    【讨论】:

    • 非常感谢您,先生,我正在试验,这将是我在 SO 上提出的最后一个类似问题
    • 不客气。在你继续学习的过程中,请不要害怕提出其他问题——这里有很多非常聪明和有才华的人。祝你好运,编码愉快!
    【解决方案2】:

    ??运算符可以帮助您轻松检查 Null 值。

    例子:

    cmd.Parameters("@OE_ID").Value = txtOEID.Text ?? DBNull.Value;
    cmd.Parameters("@OE_Category").Value = cmbCategory.Text ?? DBNull.Value;
    

    【讨论】:

    • OP 正在使用 VS 2003 - ??在 1.1 中不可用。我也相信它可能只适用于 C#。
    • 是的。它仅适用于 C#。我以为他在使用C#。对此感到抱歉。
    【解决方案3】:

    尝试对所有值使用 Inline IF

    cmd.Parameters("@OE_ID").Value = If(txtOEID.Text.Trim().Length > 0, txtOEID.Text, DBNull.Value)
    

    它的作用是先修剪字符串,然后检查其长度。如果长度大于零,则传递true 部分上的字符串,否则传递DBNull.Value

    【讨论】:

    • 将尝试先生请等待反馈
    【解决方案4】:

    由于问题将字符串转换为 int,我看到的唯一 int 是 @OE_WarrantyInclusiveYear 参数。在您的代码中,您可以安全地尝试转换为 int。

    Dim year As Integer
    If Integer.TryParse(txtWarrantyInclusiveYear.Text, year) Then
     cmd.Parameters("@OE_WarrantyInclusiveYear").Value = year
    End If
    

    【讨论】:

    • 请注意,OP 使用的是 VS 2003,所以很遗憾,Integer.TryParse 不可用。
    • 你可以自己写TryParse,把Integer.Parse包装成try catch即可。
    • 是的,你可以...但是 OP 对 VB.NET 来说似乎很新,所以我不想一次让他负担太多。
    • @tim, tomas id 切换到 Visual Studio 2008 先生
    • @ivandinglasan - 太棒了 - 很高兴听到它。 :)
    猜你喜欢
    • 2022-06-19
    • 2016-07-19
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-15
    相关资源
    最近更新 更多