Interfaces e Generics numa generalização de uma DAL

2008-08-26

Nas ultimas semanas tenho ponderado e escrito algum código relativo ao gerador de código. Até agora consegui uma interface básica com uma treeview para navegar pelos objectos e um painel de propriedades para editar as propriedades dos objectos que defini. Muito arcaico mas ainda é só uma base. Pelo menos já gera o código dos business objects como utilizo, e escreve a configuração para um ficheiro XML, usando uma classe de serialização que eu já tinha.

Agora ando a pensar e preparar a DAL, que é talvez a parte mais complexa em termos de estrutura. É mais complexo, em especial, devido à modulariedade que desejo que tenha. Em especial, o conjunto de requisitos que desejo para a DAL são:

  • possibilitar trabalhar com um conjunto de sistemas de bases de dados (SQLite, SQLServer, MySQL, Access, …) para poder facilmente gerar o código necessário para qualquer um destes sistemas.
  • permitir loggar as operações efectuadas, também para um conjunto de repositórios diferentes (bases de dados, ficheiros texto, ficheiros XML, etc..)
  • permitir gerar o código base para manipular os dados (GetItem, GetList, Save, Delete…) para os diversos sistemas de armazenamento.
  • permitir extender as classes, adicionando-lhes funcionalidade ou sobrepondo a existente na base sem afectar a geração de novo código.
  • aproveitar código já criado e as opções que o .NET oferece.

Basicamente, necessito de um género de framework para a DAL. Modelei o conceito no papel e verifiquei que iria ter que prototipar alguns conceitos para garantir o funcionamento e aperfeiçoar o método. Em especial, necessitei de testar e verificar as limitações dos generics e interfaces no C#.

O Modelo / Código

Aproveitei o snippet compiler para escrever algum código simples para testar o esquema de interfaces e generics. Imaginei que o meu gerador de código deveria gerar apenas as classes da DAL com os métodos para manipular os dados, sem ter de preocupar com o sistema de base de dados a utilizar. Compreendo que a geração de queries pode ser problemático (há ligeiras variações de sintaxe entre sistemas), mas é algo que irei procurar generalizar e resolver.

Á partida (e já era algo que tinha de outros projectos) tenho uma classe por tipo de base de dados de accesso a dados que expõe métodos de obtenção (GetItem, GetList), escrita (Save) preenchimento (Fill) de objectos na base de dados. Geralmente os métodos aceitam como parametros a query e a connection string e devolvem os objectos preenchidos ou códigos de successo. Os métodos tratam de abrir a ligação, loggar o inicio da operação, executar a query, preencher o objecto de retorno (loggando sucesso ou erros) e devolvendo o resultado. As operações são as mais “básicas” e servem para muitos tipos de operações (por exemplo, porque o meu “Save” é baseado num ExecuteNonQuery(), este serve normalmente para Inserts, Updates, e Deletes). Naturalmente, para garantir a modulariedade, as várias classes tem de ter a mesma interface.

Da mesma forma que o sistema deve permitir o acesso a dados, com uma class por tipo de base de dados, também deverá ter para cada tipo de repositório de registos (log). Naturalmente, devem ter a mesma interface.