Inserindo valores nulos em campo DateTime - Sql Server

Com a chegada da plataforma .NET, rapidamente novos recursos foram sendo disponibilizados aliados com a facilidade de desenvolvimento de programas para esta plataforma. Cedo ou tarde os programas “legados” que são aqueles que estão a anos sendo executandos dentro das empresas, acabam sendo atualizados para uma versão mais nova usando o .NET.

Esta plataforma, atualmente na versão 4.0, traz muitas vantagens para aqueles que a adotam e sem dúvida aquelas aplicações escritas para o MS-DOS em Clipper, Dataflex ou outras, acabam precisando que seus dados sejam migrados para algum banco de dados como o Sql Server ou outro.

Numa destas converões deparei-me com um problema aparentemente simples de ser resolvido, mas, que se revelou um pouco complicado: a inserção de valores nulos em campos do Sql Server.

Se o campo em questão for do tipo string tais como VarChar, Text, etc., isto fica fácil pois podemos passar um valor ou uma string vazia para este e tudo bem, mas, se estivermos trabalhando com campos do tipo DateTime pode ficar um pouco complicado.

Estou colocando aqui uma solução para o caso de você precisar fazer uma inserção de dados em tabelas do Sql Server usando C# e ADO.NET.

Considere por exemplo a seguinte classe que vai ler os dados de uma tabela do dBase/Clipper:

Listagem 1 – Definindo os campos da classe

public class ConverteDebitos
{
	public int ID { get; set; }
	public int Parcela { get; set; }
	public DateTime Emissao { get; set; }
	public DateTime Vencimento { get; set; }
	public decimal Valor { get; set; }
	public DateTime? DataLiquidacao { get; set; }
	public decimal ValorLiquidado { get; set; }
	public decimal Juros { get; set; }
	public decimal Descontos { get; set; }

	public ConverteDebitos()
	{
	}

	public void LerDadosClipper()
	{
		/// ... algum código aqui ...
	}
Estou resumindo bem a classe para evitar entrar em detalhes que não vêm ao caso agora como por exemplo a leitura dos dados da tabela do Clipper.
Esta classe procura demonstrar um caso muito comum onde, eventualmente teremos dados do tipo DateTime nulos como no caso da propriedade “DataLiquidacao”. No caso do registro do débito ainda não ter sido liquidado, este campo estará nulo e sua migração para o Sql Server deverá manter este campo assim.
Para incluir um valor nulo num campo DateTime não adianta usarmos simplesmente o valor Null do C# nem mesmo DbNull.Value. Isto irá gerar erro na execução do programa. o valor nulo para DateTime é definido como demonstra o código abaixo:
sqlCmdInsere.Parameters.Add("@DataPagto", SqlDbType.DateTime).Value = SqlDateTime.Null;
Para poder usar este código, é necessário acrescentar o seguinte "using" no programa:
using System.Data.SqlTypes;
Terminando, veja abaixo como deve ficar um método para fazer a inclusão dos dados na tabela SqlServer. Para isso funcionar, devem ser inserindos os seguintes usings:
using System.Data;
using System.Data.SqlClient;
Lista 2 – Método para inserção dos dados
	
public bool InsereRegistro(out string erro)
{
	// Define a conexao com o banco
	using (SqlConnection sqlConn = new SqlConnection("...informe sua string de conexao aqui..."))
	{
		using (SqlCommand sqlCmdInsere = new SqlCommand())
		{
			try
			{
				erro = "";
				// Define o comando que insere os dados
				sqlCmdInsere.Connection = sqlConn;
				sqlCmdInsere.CommandText = @"
				insert into debito
				(
					Id,
					Parcela,
					Emissao,
					Vencimento,
					Valor,
					DataPagto,
					ValorRecebido,
					Juros,
					Desconto
				)
				values
				(
					@Id,
					@Parcela,
					@Emissao,
					@Vencimento,
					@Valor,
					@DataPagto,
					@ValorRecebido,
					@Juros,
					@Desconto
				)";

				// inclui os parâmetros
				sqlCmdInsere.Parameters.Add("@ID", SqlDbType.Int).Value = this.ID;
				sqlCmdInsere.Parameters.Add("@Parcela", SqlDbType.Int).Value = this.Parcela;
				sqlCmdInsere.Parameters.Add("@Emissao", SqlDbType.DateTime).Value = this.Emissao;
				sqlCmdInsere.Parameters.Add("@Vencimento", SqlDbType.DateTime).Value = this.Vencimento;
				sqlCmdInsere.Parameters.Add("@Valor", SqlDbType.Decimal).Value = this.Valor;

				// neste ponto, verifica se existem algum valor no campo
				if (this.DataLiquidacao.HasValue)
				{
					sqlCmdInsere.Parameters.Add("@DataPagto", SqlDbType.DateTime).Value =
						this.DataLiquidacao.HasValue;
				}
				else
				{
					// passa valor nulo para a tabela
					sqlCmdInsere.Parameters.Add("@DataPagto", SqlDbType.DateTime).Value = SqlDateTime.Null;
				}

				sqlCmdInsere.Parameters.Add("@ValorRecebido", SqlDbType.Decimal).Value = this.ValorLiquidado;
				sqlCmdInsere.Parameters.Add("@Juros", SqlDbType.Decimal).Value = this.Juros;
				sqlCmdInsere.Parameters.Add("@Desconto", SqlDbType.Decimal).Value = this.Descontos;

				sqlConn.Open();
				sqlCmdInsere.ExecuteNonQuery();
				return true;
			}
			catch (Exception ex)
			{
				// faz tratamento de erros do código
				erro = ex.Message;
			}
			finally
			{
				if (sqlConn.State == ConnectionState.Open)
				{
					sqlConn.Close();
				}
			}

			return false;
		}
	}
}
No código acrescentei algum tratamento de erro que uso por padrão. Você pode optar por fazer isto de maneiras diferentes.
Procure explorar o namespace SqlTypes que possui ainda os seguintes tipos:
  • SqlBinary.
  • SqlBoolean.
  • SqlByte.
  • SqlDecimal.
  • SqlDouble.
  • SqlGuid.
  • SqlInt16.
  • SqlInt32.
  • SqlInt64.
  • SqlMoney.
  • SqlSingle.
  • SqlString.
  • SqlXml.
Todos estes tipos permitindo incluir valores nulos no banco de dados.
Por enquanto é isso, espero que tenha ajudado. Abraços.