web-dev-qa-db-ja.com

文字列を使用した戻り値result = Command.ExecuteScalar()エラーは、結果がnullを返すときに発生します

私はそれが以下のコードでうまく機能するデータベースから最初の行の最初のセル値を取得したいです。ただし、結果が見つからない場合は、例外がスローされます。

DBNullで処理する方法。
クエリを変更する必要がありますか?記録がない場合に値を返すのはどれですか?

System.NullReferenceException:オブジェクト参照がオブジェクトのインスタンスに設定されていません。

コード:

    public string absentDayNo(DateTime sdate, DateTime edate, string idemp)
    { 
       string result="0";
       string myQuery="select COUNT(idemp_atd) absentDayNo from td_atd where ";
       myQuery +=" absentdate_atd between '"+sdate+"' and '"+edate+" ";
       myQuery +=" and idemp_atd='"+idemp+"' group by idemp_atd ";

       SqlCommand cmd = new SqlCommand(myQuery, conn);
       conn.Open();
//System.NullReferenceException occurs when their is no data/result
       string getValue = cmd.ExecuteScalar().ToString();
         if (getValue != null)
         {
            result = getValue.ToString();
         }
         conn.Close();
        return result;
    }
26
Satinder singh

getValueはすでに文字列であるため、.ToString()を呼び出し続ける必要はありません。

それとは別に、この行はおそらくあなたの問題かもしれません:

 string getValue = cmd.ExecuteScalar().ToString();  

行がない場合、.ExecuteScalarnullを返すため、チェックを行う必要があります。

例えば:

var firstColumn = cmd.ExecuteScalar();

if (firstColumn != null) {
    result = firstColumn.ToString();
}
59
Darren

返される最初のセルがnullの場合、.NETの結果はDBNull.Valueになります

セルが返されないの場合、.NETの結果はnullになります。 nullToString()を呼び出すことはできません。もちろん、ExecuteScalarが返すものをキャプチャし、null/DBNull /その他のケースを個別に処理できます。

グループ化などをしているので、おそらく複数のグループを持つ可能性があります。率直に言って、ExecuteScalarがここでの最良の選択肢かどうかわかりません...


追加:質問のSQLは多くの点で悪いです:

  • sQLインジェクション
  • 国際化(日付がどのように見えるかについてクライアントとサーバーが同意することを望みましょう)
  • 別々のステートメントでの不要な連結

パラメータ化することを強くお勧めします。たぶんそれを簡単にするための「dapper」のようなものを使って:

int count = conn.Query<int>(
  @"select COUNT(idemp_atd) absentDayNo from td_atd
    where absentdate_atd between @sdate and @edate
    and idemp_atd=@idemp group by idemp_atd",
    new {sdate, edate, idemp}).FirstOrDefault();

「行なし」シナリオを含むすべての問題が解決されました。日付は(文字列ではなく)日付として渡されます。注入口はパラメータを使用して閉じられます。追加のボーナスとしてクエリプランの再利用もできます。ここでgroup byは冗長です、ところで-グループが1つしかない場合(等価条件を介して)、COUNT(1)を選択するだけでもかまいません。

19
Marc Gravell

これを試して

var getValue = cmd.ExecuteScalar();    
conn.Close();
return (getValue == null) ? string.Empty : getValue.ToString();
10
Rajeev Kumar

次のように使用できます

string result = null;
object value = cmd.ExecuteScalar();
 if (value != null)
 {
    result = value.ToString();
 }     
 conn.Close();
return result;
5
Saravanan

値はnullではなく、DBNull.Valueです。

object value = cmd.ExecuteScalar();
if(value == DBNull.Value)
4
Jānis

これを試して :

 string getValue = Convert.ToString(cmd.ExecuteScalar());
2
Naresh Parmar

これは動作するはずです:

var result = cmd.ExecuteScalar();
conn.Close();

return result != null ? result.ToString() : string.Empty;

また、クエリでパラメーターを使用することをお勧めします(次のような提案です)。

var cmd = new SqlCommand
{
    Connection = conn,
    CommandType = CommandType.Text,
    CommandText = "select COUNT(idemp_atd) absentDayNo from td_atd where absentdate_atd between @sdate and @edate and idemp_atd=@idemp group by idemp_atd"
};

cmd.Parameters.AddWithValue("@sdate", sdate);
cmd.Parameters.AddWithValue("@edate", edate);
// etc ...
1

SQLサーバーのisnull関数を使用する

public string absentDayNo(DateTime sdate, DateTime edate, string idemp)
{ 
    string result="0";
    string myQuery="select isnull(COUNT(idemp_atd),0) as absentDayNo from td_atd where ";
    myQuery +=" absentdate_atd between '"+sdate+"' and '"+edate+" ";
    myQuery +=" and idemp_atd='"+idemp+"' group by idemp_atd ";

    SqlCommand cmd = new SqlCommand(myQuery, conn);
    conn.Open();
    //System.NullReferenceException occurs when their is no data/result
    string getValue = cmd.ExecuteScalar().ToString();
    if (getValue != null)
    {
        result = getValue.ToString();
    }
    conn.Close();
    return result;
}
0
hussien

C#の高度な機能があり、その「?」を使用します。 。 string getValue = cmd.ExecuteScalar()?. ToString();すべてに感謝します。

0
Muzafar Hussain