SQL Data Reader – manipulando valores da coluna Null

Eu estou usando um SQLdatareader para construir POCOs de um database. O código funciona, exceto quando encontra um valor nulo no database. Por exemplo, se a coluna FirstName no database contiver um valor nulo, uma exceção será lançada.

employee.FirstName = sqlreader.GetString(indexFirstName); 

Qual é a melhor maneira de lidar com valores nulos nessa situação?

    Você precisa verificar IsDBNull :

     if(!SqlReader.IsDBNull(indexFirstName)) { employee.FirstName = sqlreader.GetString(indexFirstName); } 

    Essa é sua única maneira confiável de detectar e lidar com essa situação.

    Eu envolvi essas coisas em methods de extensão e tendem a retornar um valor padrão se a coluna for de fato null :

     public static string SafeGetString(this SqlDataReader reader, int colIndex) { if(!reader.IsDBNull(colIndex)) return reader.GetString(colIndex); return string.Empty; } 

    Agora você pode chamar assim:

     employee.FirstName = SqlReader.SafeGetString(indexFirstName); 

    e você nunca terá que se preocupar com uma exceção ou um valor null novamente.

    Você deve usar o operador as combinado com o ?? operador para valores padrão. Os tipos de valor precisarão ser lidos como anuláveis ​​e receberão um padrão.

     employee.FirstName = sqlreader[indexFirstName] as string; employee.Age = sqlreader[indexAge] as int? ?? default(int); 

    O operador as manipula a conversão, incluindo a verificação para DBNull.

    Para uma string, você pode simplesmente converter a versão do object (acessada usando o operador array) e terminar com uma string nula para nulls:

     employee.FirstName = (string)sqlreader[indexFirstName]; 

    ou

     employee.FirstName = sqlreader[indexFirstName] as string; 

    Para inteiros, se você converter para um int anulável, você pode usar GetValueOrDefault ()

     employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault(); 

    ou o operador de coalescência de nulo ( ?? ).

     employee.Age = (sqlreader[indexAge] as int?) ?? 0; 

    IsDbNull(int) é geralmente muito mais lento do que usando methods como GetSqlDateTime e, em seguida, comparando com DBNull.Value . Tente esses methods de extensão para SqlDataReader .

     public static T Def(this SqlDataReader r, int ord) { var t = r.GetSqlValue(ord); if (t == DBNull.Value) return default(T); return ((INullable)t).IsNull ? default(T) : (T)t; } public static T? Val(this SqlDataReader r, int ord) where T:struct { var t = r.GetSqlValue(ord); if (t == DBNull.Value) return null; return ((INullable)t).IsNull ? (T?)null : (T)t; } public static T Ref(this SqlDataReader r, int ord) where T : class { var t = r.GetSqlValue(ord); if (t == DBNull.Value) return null; return ((INullable)t).IsNull ? null : (T)t; } 

    Use-os assim:

     var dd = r.Val(ords[4]); var ii = r.Def(ords[0]); int nn = r.Def(ords[0]); 

    Uma maneira de fazer isso é verificar os valores nulos do db:

     employee.FirstName = (sqlreader.IsDBNull(indexFirstName) ? "" : sqlreader.GetString(indexFirstName)); 

    Eu não acho que haja um valor de coluna NULL , quando as linhas são retornadas dentro de um datareader usando o nome da coluna.

    Se você fizer datareader["columnName"].ToString(); sempre lhe dará um valor que pode ser uma string vazia ( String.Empty se você precisar comparar).

    Eu usaria o seguinte e não me preocuparia muito:

     employee.FirstName = sqlreader["columnNameForFirstName"].ToString(); 

    Esta solução é menos dependente do fornecedor e funciona com um SQL, OleDB e MySQL Reader:

     public static string GetStringSafe(this IDataReader reader, int colIndex) { return GetStringSafe(reader, colIndex, string.Empty); } public static string GetStringSafe(this IDataReader reader, int colIndex, string defaultValue) { if (!reader.IsDBNull(colIndex)) return reader.GetString(colIndex); else return defaultValue; } public static string GetStringSafe(this IDataReader reader, string indexName) { return GetStringSafe(reader, reader.GetOrdinal(indexName)); } public static string GetStringSafe(this IDataReader reader, string indexName, string defaultValue) { return GetStringSafe(reader, reader.GetOrdinal(indexName), defaultValue); } 

    reader.IsDbNull(ColumnIndex) funciona como muitas respostas.

    E eu quero mencionar se você está trabalhando com nomes de coluna, apenas comparando os tipos pode ser mais confortável.

     if(reader["TeacherImage"].GetType() == typeof(DBNull)) { //logic } 

    O que eu costumo fazer é replace os valores nulos na instrução SELECT por algo apropriado.

     SELECT ISNULL(firstname, '') FROM people 

    Aqui eu substituo cada nulo por uma string em branco. Seu código não lançará um erro nesse caso.

    Verifique sqlreader.IsDBNull(indexFirstName) antes de tentar lê-lo.

    Eu acho que você gostaria de usar:

     SqlReader.IsDBNull(indexFirstName) 

    Você pode escrever uma function genérica para verificar Nulo e include o valor padrão quando for NULL. Chame isso ao ler o Datareader

     public T CheckNull(object obj) { return (obj == DBNull.Value ? default(T) : (T)obj); } 

    Ao ler o uso do Datareader

      while (dr.Read()) { tblBPN_InTrRecon Bpn = new tblBPN_InTrRecon(); Bpn.BPN_Date = CheckNull(dr["BPN_Date"]); Bpn.Cust_Backorder_Qty = CheckNull(dr["Cust_Backorder_Qty"]); Bpn.Cust_Min = CheckNull(dr["Cust_Min"]); } 

    como criar methods auxiliares

    Para corda

     private static string MyStringConverter(object o) { if (o == DBNull.Value || o == null) return ""; return o.ToString(); } 

    Uso

     MyStringConverter(read["indexStringValue"]) 

    Para o Int

      private static int MyIntonverter(object o) { if (o == DBNull.Value || o == null) return 0; return Convert.ToInt32(o); } 

    Uso

     MyIntonverter(read["indexIntValue"]) 

    Por data

     private static DateTime? MyDateConverter(object o) { return (o == DBNull.Value || o == null) ? (DateTime?)null : Convert.ToDateTime(o); } 

    Uso

     MyDateConverter(read["indexDateValue"]) 

    Nota: para DateTime declare varialbe como

     DateTime? variable; 

    Usamos uma série de methods estáticos para extrair todos os valores dos nossos leitores de dados. Então, nesse caso, estaríamos chamando DBUtils.GetString(sqlreader(indexFirstName)) O benefício de criar methods estáticos / compartilhados é que você não precisa fazer as mesmas verificações repetidamente …

    O (s) método (s) estático (s) conteria código para verificar nulos (veja outras respostas nesta página).

    Pergunta antiga, mas talvez alguém ainda precise de uma resposta

    na verdade eu trabalhei em torno desta questão assim

    Para int:

     public static object GatDataInt(string Query, string Column) { SqlConnection DBConn = new SqlConnection(ConnectionString); if (DBConn.State == ConnectionState.Closed) DBConn.Open(); SqlCommand CMD = new SqlCommand(Query, DBConn); SqlDataReader RDR = CMD.ExecuteReader(); if (RDR.Read()) { var Result = RDR[Column]; RDR.Close(); DBConn.Close(); return Result; } return 0; } 

    o mesmo para string apenas retorna “” em vez de 0 como “” é string vazia

    então você pode usá-lo como

     int TotalPoints = GatDataInt(QueryToGetTotalPoints, TotalPointColumn) as int?; 

    e

     string Email = GatDatastring(QueryToGetEmail, EmailColumn) as string; 

    muito flexível para que você possa inserir qualquer consulta para ler qualquer coluna e ela nunca retornará com erro

    Eu estou usando o código listado abaixo para manipular células nulas em uma planilha do Excel que é lida em uma tabela de dados.

     if (!reader.IsDBNull(2)) { row["Oracle"] = (string)reader[2]; } 
     private static void Render(IList list, IDataReader reader) { while (reader.Read()) { listData.DownUrl = (reader.GetSchemaTable().Columns["DownUrl"] != null) ? Convert.ToString(reader["DownUrl"]) : null; //没有这一列时,让其等于null list.Add(listData); } reader.Close(); } 

    e / ou usar o operador ternário com atribuição:

     employee.FirstName = rdr.IsDBNull(indexFirstName))? String.Empty: rdr.GetString(indexFirstName); 

    substitua o valor padrão (quando nulo) conforme apropriado para cada tipo de propriedade …

    Esse método é dependente de indexFirstName, que deve ser o ordinal da coluna com base em zero.

     if(!sqlReader.IsDBNull(indexFirstName)) { employee.FirstName = sqlreader.GetString(indexFirstName); } 

    Se você não souber o índice da coluna, mas não quiser verificar um nome, poderá usar este método de extensão:

     public static class DataRecordExtensions { public static bool HasColumn(this IDataRecord dr, string columnName) { for (int i=0; i < dr.FieldCount; i++) { if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase)) return true; } return false; } } 

    E use o método assim:

     if(sqlReader.HasColumn("FirstName")) { employee.FirstName = sqlreader["FirstName"]; } 

    Você pode usar o operador condicional:

     employee.FirstName = sqlreader["indexFirstName"] != DBNull.Value ? sqlreader[indexFirstName].ToString() : ""; 

    você pode sempre verificar isso também

     if(null !=x && x.HasRows) { ....}