Paul Kimmel

 

Já é sabido que existe uma “incompatibilidade” de conceitos entre objetos e bancos de dados relacionais. Todos sabem disso, e existem várias iniciativas para lidar com esta dificuldade. Um exemplo seria o surgimento dos bancos de dados orientados a objeto.

Existem várias iniciativas de grandes empresas para lidar com este cenário. A Microsoft, por exemplo, está trabalhando no ADO.NET Entity Framework, além  de outras soluções já conhecidas. A questão é que enquanto a solução “definitiva” não surge, precisamos continuar o desenvolvimento de nossas aplicações.

Neste contexto, este artigo tem como objetivo apresentar algumas idéias sobre como retirar muito do trabalho da criação de uma camada de acesso a informações usando algumas das características mais novas do .NET, tais como os tipos genéricos e nulos  e alguns staples, como Reflection.

Usando campos nulos para entidades

No universo .NET, parte da incompatibilidade entre objetos e entidades (ver Nota 1) está no fato de que os bancos de dados permitem valores nulos para tipos de dados como Inteiros, mas o Framework .NET não. Conseqüentemente, quando alguma pessoa acessa uma coluna de um banco de dados, é necessário verificar a existência de valores nulos. Isto é uma dor de cabeça e frequentemente conduz a erros ao povoar entidades de uma tabela de banco de dados.

 

Nota 1. Descrição de Entidade

Uma entidade é tradicionalmente uma tabela do banco de dados. Uma classe entidade é geralmente uma classe que represente uma tabela do banco de dados. A maior parte dos domínios dos softwares possui diversas classes de entidade para dados persistidos e duas ou três vezes mais classes para classes que não representam entidades do domínio.

 

Os números inteiros não poderiam tradicionalmente ser nulos porque eram tipos de valor (ou tipos primitivos), e tipos de valor não são referências como string, por exemplo. Com a classe Nullable(Of T) (ver Nota 2), você pode declarar campos como Anuláveis. Isto significa que um campo de número inteiro pode ser declarado como Nullable(Of Integer) e atribuir o valor NULL ou um número inteiro válido. Isto retira algum trabalho de povoar classes da entidade das tabelas de banco de dados que têm valores nulos.

 

Nota 2. Tipos Genéricos

Se você ainda está conhecendo tipos genéricos – também chamados de template (modelo) ou tipos parametrizados – a característica mais importante a saber é que os tipos genéricos separam o algoritmo em relação ao tipo de dado, ou seja, você define um algoritmo genérico e pode passar qualquer tipo de dado para aquele algoritmo. O parâmetro T é usado para indicar que a classe fornece o comportamento e você fornece o tipo T.

 

A classe de Nullable(Of T) trabalha usando alguns métodos e operadores sobrecarregados, e faz essencialmente o que qualquer um de nós faríamos. Se a variável Nullable tiver um valor para T, este é retornado. Caso contrário, algum valor padrão equivalente é retornado, quando você escreve código como o descrito na Listagem 1.

 

Listagem 1. Um simples aplicativo de console que introduz tipos anuláveis

Module Module1

   Sub Main()

      Dim I As Nullable(Of Integer)

      I = 5

      Console.WriteLine(I)

      Console.ReadLine()

   End Sub

End Module

 

Na Listagem 1, I é o tipo de número inteiro anulável. A declaração atribuindo 5 para I na verdade chama “Nullable.Operator CType(ByVal value as T) As T?”, que é um operador de conversão que converte T, neste caso um valor do tipo inteiro, em um Nullable (Of T). A Listagem 2 mostra o operador de conversão desmontado.

 

Listagem 2. Atribuindo um dado não-anulável a um anulável. Chama um operador de conversão compartilhado convertendo T para T?. T? é a anotação  abreviada de C# para tipos anuláveis.

Public Shared Widening Operator CType(ByVal value As T) As T?

   Return New T?(value)

End Function

 

Você pode usar a classe Nullable genérica para definir uma classe de entidade para a tabela Empregados. Você não necessita usar a classe Nullable para atributos do tipo nvarchars (basicamente strings), mas pode usá-los para tipos tais como Inteiros e DateTime. A Listagem 3 demonstra uma classe de entidade condensada para a tabela Empregados, chamada Employee.

 

Listagem 3. A classe Employee usando tipos nulos.

Public Class Employee

 

   Private FEmployeeID As Nullable(Of Integer)

   Public Property EmployeeID() As Nullable(Of Integer)

      Get

         Return FEmployeeID

      End Get

      Set(ByVal Value As Nullable(Of Integer))

         If (Value.HasValue = False) Then

            Console.WriteLine("Employee ID is null")

         End If

         FEmployeeID = Value

      End Set

   End Property

 

   Private FLastName As String

   Public Property lastName() As String

      Get

         Return FLastName

      End Get

      Set(ByVal Value As String)

         FLastName = Value

      End Set

   End Property

 

   Private FFirstName As String

   Public Property FirstName() As String

      Get

         Return FFirstName

      End Get

      Set(ByVal Value As String)

         FFirstName = Value

      End Set

   End Property

 

   Private FBirthDate As Nullable(Of DateTime)

   Public Property BirthDate() As Nullable(Of DateTime)

      Get

         Return FBirthDate

      End Get

      Set(ByVal Value As Nullable(Of DateTime))

         FBirthDate = Value

      End Set

   End Property

 

   Private FPhoto As Byte()

   Public Property Photo() As Byte()

      Get

         Return FPhoto

      End Get

      Set(ByVal Value As Byte())

         FPhoto = Value

      End Set

   End Property

 

   Public Overrides Function ToString() As String

      Return String.Format("Employee: {0} {1}, {2} is in {3}", _

         FEmployeeID, FLastName, FFirstName, FRegion)

   End Function

 

   Private FRegion As String

   Public Property Region() As String

      Get

         Return FRegion

      End Get

      Set(ByVal Value As String)

         FRegion = Value

      End Set

   End Property

 

End Class

 

Na Listagem 3, EmployeeID e BirthDate são tipos anuláveis. Todos os outros tipos são strings ou uma foto que é uma matriz de bytes, ambos aos quais já se pode atribuir valores nulos. Na vida real, uma chave primária provavelmente será nula somente quando você criar uma entidade nova, e registros de empregado geralmente têm datas de nascimento. No entanto, o objetivo da listagem foi demonstrar como aplicar a classe de Nullable.

Agora, se acontecer de você ler um valor nulo para os atributos BirthDate ou o EmployeeID, você pode com segurança atribuí-lo ao campo sem todo aquele código, que costumamos chamar de ”gambiarra”, procurando por valore nulos.