【问题标题】:Object cannot be cast from DBNull to other types对象不能从 DBNull 转换为其他类型
【发布时间】:2011-08-31 05:11:42
【问题描述】:

对象不能从 DBNull 转换为其他类型。

我有一个引发上述错误的函数。我正在处理存储过程和 C# 代码中的所有空值。

那么它是从哪里得到这个错误的呢?

我可以在 catch 块中看到错误。但我不明白以下 create() 中的哪一行出现错误。

public Boolean Create(DataTO DataTO)
{
    IDbTrans transaction = null;
    IDbCmd IDbCmd;

    string EncryptedPassword = Encrypt(DataTO.txtPwd);
    Base dataAccCom = null;

    try
    {
        dataAccCom = Factory.Create();
        dataAccCom.OpenConnection();
        transaction = dataAccCom.BeginTransaction();
        IDbCmd = dataAccCom.CreateCommand("sp_Register", true);
        dataAccCom.AddParameter(IDbCmd, "op_Id", DbType.Int64, 0, ParameterDirection.Output);
        dataAccCom.AddParameter(IDbCmd, "p_dlstTitle", DbType.String, ReplaceNull(DataTO.dlstTitle));
        dataAccCom.AddParameter(IDbCmd, "p_txtFirstName", DbType.String, ReplaceNull(DataTO.txtFirstName));
        dataAccCom.AddParameter(IDbCmd, "p_txtMiddleName", DbType.String, ReplaceNull(DataTO.txtMiddleName));
        dataAccCom.AddParameter(IDbCmd, "p_txtLastName", DbType.String, ReplaceNull(DataTO.txtLastName));
        dataAccCom.AddParameter(IDbCmd, "p_txtDob", DbType.DateTime, DataTO.txtDob);
        dataAccCom.AddParameter(IDbCmd, "p_txtDesig", DbType.String, ReplaceNull(DataTO.txtDesig));
        dataAccCom.AddParameter(IDbCmd, "p_txtOFlatNo", DbType.String, ReplaceNull(DataTO.txtOFlatNo));
        dataAccCom.AddParameter(IDbCmd, "p_txtOBuild", DbType.String, ReplaceNull(DataTO.txtOBuild));
        dataAccCom.AddParameter(IDbCmd, "p_txtOPost", DbType.String, ReplaceNull(DataTO.txtOPost));
        dataAccCom.AddParameter(IDbCmd, "p_txtOArea", DbType.String, ReplaceNull(DataTO.txtOArea));
        dataAccCom.AddParameter(IDbCmd, "p_txtOCity", DbType.String, ReplaceNull(DataTO.txtOCity));
        dataAccCom.AddParameter(IDbCmd, "p_txtRBuild", DbType.String, ReplaceNull(DataTO.txtRBuild));
        dataAccCom.AddParameter(IDbCmd, "p_txtRPost", DbType.String, ReplaceNull(DataTO.txtRPost));
        dataAccCom.AddParameter(IDbCmd, "p_txtUserID", DbType.String,ReplaceNull(DataTO.txtUserID));
        dataAccCom.AddParameter(IDbCmd, "p_txtPwd", DbType.String, ReplaceNull(EncryptedPassword));
        dataAccCom.ExecuteNonQuery(IDbCmd);
        DataTO.Id = Convert.ToInt64(dataAccCom.GetParameterValue(IDbCmd, "op_Id"));
        transaction.Commit();
        return true;



    }
    catch (System.Exception ex)
    {
        if (transaction != null)
        {
            transaction.Rollback();
        }
        throw ex;
    }
    finally
    {
        transaction = null;
        if (dataAccCom != null)
        {
            dataAccCom.CloseConnection();
        }
        dataAccCom = null;
        IDbCmd = null;
    }
}

public string ReplaceNull(string value)
{
    if (value == null)
    {
        return "";
    }
    else
    {
        return value;
    }
}

public DateTime ReplaceNull(DateTime value)
{
    if (value == null)
    {
        return DateTime.Now;
    }
    else
    {
        return value;
    }
}

public double ReplaceNull(double value)
{
    if (value == null)
    {
        return 0.0;
    }
    else
    {
        return value;
    }
}

【问题讨论】:

  • 请注意,ReplaceNulldoubleDateTime 的重载毫无价值。这些类型的值永远不能为空,因此永远不会通过if (value == null) 条件。
  • 当然,除非它们可以为空,但那是另一回事了。
  • 你有没有通过这个方法?在 Visual Studio 中,考虑中断所有异常 (Ctrl+Alt+E) 并查看实际导致问题的行。
  • 哇,哇!不要“throw ex”,只是“throw”,否则你会失去一些痕迹。这并不能解决您的问题,但它是养成做事习惯的好习惯。
  • ^^ 我总是在学习新东西。就在我认为我知道我需要了解异常的时候......

标签: c# .net asp.net parameters


【解决方案1】:

我认为您的输出参数返回的是 DBNull 值。像这样添加支票

var outputParam = dataAccCom.GetParameterValue(IDbCmd, "op_Id");
if(!(outputParam is DBNull))
     DataTO.Id = Convert.ToInt64(outputParam);

【讨论】:

  • 也许更好Convert.IsDBNull()?
  • 我的查询中有多个整数值。我可以以某种方式缩短流程还是我必须为每个人都这样做?
  • @Alexander,我希望您在此之前找到答案,但是比这更短会变得非常难看,但是使用 s 三元组会起作用: DataTO.Id = dataAccCom.GetParameterValue(IDbCmd, " op_Id") == DBNull.Value ? null : Convert.ToInt64(dataAccCom.GetParameterValue(IDbCmd, "op_Id"));
【解决方案2】:

我怀疑这条线

DataTO.Id = Convert.ToInt64(dataAccCom.GetParameterValue(IDbCmd, "op_Id"));

导致问题。 op_Id 值是否可能被存储过程设置为 null?

要防止它使用Convert.IsDBNull 方法。例如:

if (!Convert.IsDBNull(dataAccCom.GetParameterValue(IDbCmd, "op_Id"))
{
 DataTO.Id = Convert.ToInt64(dataAccCom.GetParameterValue(IDbCmd, "op_Id"));
}
else 
{
 DataTO.Id = ...some default value or perform some error case management
}

【讨论】:

    【解决方案3】:

    您需要检查DBNull,而不是null。此外,您的三个 ReplaceNull 方法中有两个没有意义。 doubleDateTime 不可为空,因此检查它们是否为 null 将始终为 false...

    【讨论】:

      【解决方案4】:

      TryParse 通常是处理这类事情最优雅的方式:

      long temp = 0;
      if (Int64.TryParse(dataAccCom.GetParameterValue(IDbCmd, "op_Id").ToString(), out temp))
      {
         DataTO.Id = temp;
      }     
      

      【讨论】:

        【解决方案5】:

        错误原因:在面向对象的编程语言中,null 表示没有对对象的引用。 DBNull 表示未初始化的变体或不存在的数据库列。来源:MSDN

        我遇到错误的实际代码:

        改代码前:

            if( ds.Tables[0].Rows[0][0] == null ) //   Which is not working
        
             {
                    seqno  = 1; 
              }
            else
            {
                  seqno = Convert.ToInt16(ds.Tables[0].Rows[0][0]) + 1;
             }
        

        修改代码后:

           if( ds.Tables[0].Rows[0][0] == DBNull.Value ) //which is working properly
                {
                            seqno  = 1; 
                 }
                    else
                    {
                          seqno = Convert.ToInt16(ds.Tables[0].Rows[0][0]) + 1;
                     }
        

        结论:当数据库值返回空值时,我们建议使用DBNull类,而不是像C#语言那样只指定为空。

        【讨论】:

          【解决方案6】:

          对于从 google 到达此页面的其他人:

          DataRow 还有一个函数.IsNull("ColumnName")

              public DateTime? TestDt; 
              public Parse(DataRow row)
              {
                  if (!row.IsNull("TEST_DT"))
                      TestDt = Convert.ToDateTime(row["TEST_DT"]);
              }
          

          【讨论】:

            【解决方案7】:

            我今天遇到了这个问题,并通过检查映射类解决了它。我有一个类,它有 5 个属性,从存储过程返回的 5 个列被映射到这些属性。这些属性是不可为空的,因此我得到了错误。我使它们可以为空,问题得到解决。

                public int? Pause { get; set; }
                public int? Delay { get; set; }
                public int? Transition { get; set; }
                public int? TransitionTime { get; set; }
                public int? TransitionResolution { get; set; }
            

            添加了“?”使用数据类型使它们可以为空。

            其次,我还在存储过程中添加了isNull检查,如下:

                isnull(co_pivot.Pause, 0) as Pause,
                isnull(co_pivot.Delay, 0) as Delay,
                isnull(co_pivot.Transition, 0) as Transition,
                isnull(co_pivot.TransitionTime, 0) as TransitionTime,
                isnull(co_pivot.TransitionResolution, 0) as TransitionResolution
            

            希望这对某人有所帮助。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-12-21
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多