"System.DBNull" türündeki nesne "System.String" türüne dönüştürülemiyor


109

Uygulamamda yukarıdaki hatayı aldım. İşte orijinal kod

public string GetCustomerNumber(Guid id)
{
     string accountNumber = 
          (string)DBSqlHelperFactory.ExecuteScalar(connectionStringSplendidmyApp, 
                          CommandType.StoredProcedure, 
                          "GetCustomerNumber", 
                          new SqlParameter("@id", id));
     return accountNumber.ToString();
 }

İle değiştirdim

public string GetCustomerNumber(Guid id)
{
   object accountNumber =  
          (object)DBSqlHelperFactory.ExecuteScalar(connectionStringSplendidCRM, 
                                CommandType.StoredProcedure, 
                                "spx_GetCustomerNumber", 
                                new SqlParameter("@id", id));
    if (accountNumber is System.DBNull)
    {
       return string.Empty;
    }
    else
    {
       return accountNumber.ToString();
    }
}

Bunun daha iyi bir yolu var mı?


2
@ rein'in cevabına gerçekten bakmalısınız, uzun vadede size çok zaman kazandıracak
roman m

Yanıtlar:


90

Daha kısa bir form kullanılabilir:

return (accountNumber == DBNull.Value) ? string.Empty : accountNumber.ToString()

DÜZENLEME: ExecuteScalar'a dikkat etmedim. Alan dönüş sonucunda yoksa gerçekten boş döndürür. Bunun yerine şunu kullanın:

return (accountNumber == null) ? string.Empty : accountNumber.ToString() 

3
Bu olmaz iş - "AccountNumber" dir değil , bir veritabanı değer ama düzenli eski Düz Eski .NET "nesne" örneği - Normal "boş" değerine karşı kontrol etmeniz gerekir. DBNull.Value bir SqlDataReader veya bir SqlParameter için çalışır - ancak buradaki bu nesne için geçerli değildir.
marc_s

Haklısın, durum kontrolü kısmını optimize etmeye başladım, daha önce satıra bakmadım. Mea Culpa.
Kullanıcı

Yazınızda, düzenleme 6 karakterin değiştirilmesini gerektirdiği için gerçekten düzenleyemediğim bir yazım hatası var. Birisi accountNumber.TosString () 'i accountNumber.ToString () olarak değiştirebilir mi
Eric

@marc_s db / sorgu düzenine bağlı olarak, ikisini veya ikisini birden kontrol etmeniz gerekir. WHERE herhangi bir satırla eşleşmiyorsa null, seçilen satır NULLbu sütunda varsa, dönüş değeri şudur System.DBNull.
Alexander

İlk durumda @Alexander, herhangi bir satırla eşleşmiyorsa, null'dan dönüştürürken döndürdükleri değerde sorun yoksa, Convert.ToString veya başka bir Convert yöntemine güvenebilirsiniz: dizeler için boş dize, sayısal değerler için 0, yanlış boole için, DateTime için MinValue ... msdn.microsoft.com/en-us/library/vstudio/…
Jaime

199

Basit bir genel işlevle bunu çok kolaylaştırabilirsiniz. Sadece şunu yap:

return ConvertFromDBVal<string>(accountNumber);

işlevi kullanarak:

public static T ConvertFromDBVal<T>(object obj)
{
    if (obj == null || obj == DBNull.Value)
    {
        return default(T); // returns the default value for the type
    }
    else
    {
        return (T)obj;
    }
}

1
Evet, bunun gibi bir işlev tek pratik çözümdür. Bin kez kopyalayıp yapıştırdıktan sonra her türlü satır içi mantık başarısız olacaktır. :-)
Christian Hayter

3
1'i bool'e dönüştürmeyi denerseniz bu işe yaramayacaktır (Convert.ToBoolean (1) iyi çalışır)
roman m

@roman: öyleyse, boole türünü kontrol eden ek bir kontrol (boşluğu kontrol etmeden önce)
isteyeceğiz

1
Dönüştürme işlevlerini kullanmak istiyorsanız veya kullanmanız gerekiyorsa, bu çalışmıyor demektir. Açık bir kadroya dönüştürmeyi tercih edebileceğiniz birkaç senaryo vardır. @romanm bunlardan birini kaydetti. Bir diğeri, ondalık sayılarla çalıştığınız ve Convert.ToInt32 ve (int) 'in kullandığı farklı yuvarlama mekanizmalarını önemsediğiniz zamandır. İlki en yakın çift değere yuvarlarken, açık çevrim değeri keser: stackoverflow.com/questions/1608801/… Mümkünse, T-SQL ISNULL işlevi
Jaime

2
@Jaime Bu işlevin, bir SQL veri türünden bir C # /. NET veri türüne örtük bir dönüştürme işlevi görmesi beklenir. Açık bir atama ihtiyacınız varsa, bu işlevi kullanmayın - bunun yerine açıkça yapın.
dizgin

17

ExecuteScalar geri dönecek

  • sonuç kümesi yoksa null
  • aksi takdirde, sonuç kümesinin ilk satırının ilk sütunu, bu DBNull olabilir.

Sonuç kümesinin ilk sütununun bir dize olduğunu biliyorsanız, tüm tabanları kapsamak için hem null hem de DBNull'u kontrol etmeniz gerekir. Gibi bir şey:

object accountNumber = ...ExecuteScalar(...);
return (accountNumber == null) ? String.Empty : accountNumber.ToString();

Yukarıdaki kod, DBNull.ToString'in boş bir dize döndürdüğü gerçeğine dayanır.

AccountNumber başka bir tür olsaydı (tamsayı diyelim), o zaman daha açık olmanız gerekir:

object accountNumber = ...ExecuteScalar(...);
return (accountNumber == null || Convert.IsDBNull(accountNumber) ?     
         (int) accountNumber : 0;

Sonuç kümenizin her zaman en az bir satıra sahip olacağından eminseniz (örn. SELECT COUNT (*) ...), o zaman null kontrolünü atlayabilirsiniz.

Sizin durumunuzda "System.DBNull" türündeki nesne "System.String" türüne dönüştürülemiyor "hata mesajı, sonuç kümenizin ilk sütununun bir DBNUll değeri olduğunu gösterir. Bu, ilk satırdaki diziden diziye:

string accountNumber = (string) ... ExecuteScalar(...);

Marc_s'in DBNull.Value için kontrol etmeniz gerekmediği yorumu yanlış.


sonuç kümem her zaman bir satır döndürmeyecek.
Saif Khan

6

C # 'ın boş birleştirme operatörünü kullanabilirsiniz

return accountNumber ?? string.Empty;

-1: Bu derlenmeyecek: yöntem bir dize döndürür ve accountNumber bir nesnedir.
Joe

2
return Cmd.ExecuteScalar (). ToString () ?? String.Empty;
Chaitanya

return Cmd.ExecuteScalar (). ToString () işi benim için yaptı
Taran

3

Bu sorunu çözmenin başka bir yolu var. Mağaza prosedürünüzü değiştirmeye ne dersiniz? ISNULL (alanınız, "") sql işlevini kullanarak, dönüş değeri null ise boş dizge döndürebilirsiniz.

Daha sonra orijinal sürüm olarak temiz kodunuz var.


3

Bu, DBNull.Value olabilecek herhangi bir nesneyi dönüştürmek için kullandığım genel yöntemdir:

public static T ConvertDBNull<T>(object value, Func<object, T> conversionFunction)
{
    return conversionFunction(value == DBNull.Value ? null : value);
}

kullanımı:

var result = command.ExecuteScalar();

return result.ConvertDBNull(Convert.ToInt32);

daha kısa:

return command
    .ExecuteScalar()
    .ConvertDBNull(Convert.ToInt32);

2

Sanırım bunu şu şekilde yapabilirsiniz:

string accountNumber = DBSqlHelperFactory.ExecuteScalar(...) as string;

AccountNumber null ise dize değil DBNull olduğu anlamına gelir :)


Veya return (accountNumber as string) ?? string.Empty;, accountNumber hala bir object. Veritabanınızı kendi hattında tutmayı tercih ederseniz.
Brian

1

String.Concat, DBNull ve null değerleri boş bir dizeye dönüştürür.

public string GetCustomerNumber(Guid id)
{
   object accountNumber =  
          (object)DBSqlHelperFactory.ExecuteScalar(connectionStringSplendidCRM, 
                                CommandType.StoredProcedure, 
                                "spx_GetCustomerNumber", 
                                new SqlParameter("@id", id));

    return String.Concat(accountNumber);

 }

Ancak, kod anlaşılabilirliği konusunda bir şeyler kaybettiğinizi düşünüyorum


1
Yazarsan ne olur return "" + accountNumber;?
Zev Spitz

0

Boş olmayan bir örnek aldığım için ve DBNULL ile karşılaştırırsam bir istisna elde ettim Operator '==' cannot be applied to operands of type 'string' and 'system.dbnull've NULL ile karşılaştırmak için değiştirmeye çalışırsam, işe yaramadı (DBNull bir nesne olduğu için) kabul edilen cevap olsa bile.

Sadece 'eşittir' anahtar kelimesini kullanmaya karar verdim. Sonuç çok okunabilir:

data = (item is DBNull) ? String.Empty : item


-1

Bu sorunu benim için ortadan kaldırmak için bir uzantı kullanıyorum, peşinde olduğunuz şey olabilir veya olmayabilir.

Bu böyle devam ediyor:

public static class Extensions
{

    public String TrimString(this object item)
    {
        return String.Format("{0}", item).Trim();
    }

}

Not:

Bu uzantı değil dönmek nulldeğerleri! Öğe nullveya DBNull.Value ise boş bir String döndürür.

Kullanımı:

public string GetCustomerNumber(Guid id)
{
    var obj = 
        DBSqlHelperFactory.ExecuteScalar(
            connectionStringSplendidmyApp, 
            CommandType.StoredProcedure, 
            "GetCustomerNumber", 
            new SqlParameter("@id", id)
        );
    return obj.TrimString();
}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.