Organize classes C ++ em torno do banco de dados SQL

5

Minha pergunta é sobre como organizar melhor as classes C ++ em um banco de dados modelo, e eu entendo isso pode parecer muito elementar.

O software que eu proponho criar fará o seguinte. Destina-se a pequenos fabricantes de FMCG e usará o Qt.

  • O software registrará não conformidades, reclamações de produtos, ações corretivas e servir como uma manutenção eletrônica de registros
  • Haverá um pouco de "lógica de negócios", como o destaque Este recurso destina-se a ser relatórios abrangentes, pesquisas e análise, bem como uma abordagem flexível para inserir dados para suavizar fluxos de trabalho (ou seja, um intervalo da "uma tela por estágio do processo" paradigma)
  • O armazenamento persistente é um banco de dados SQL, com uma tabela para cada tipo de registro (alguns registros serão divididos em tabelas separadas para investigações / soluções. Isso significa que a maioria do trabalho será feito em um única linha).
  • Cada cliente que usa este software exigirá emendas, colunas / campos adicionais ou alterações nos nomes das colunas e talvez logíca de negócios. Cada cliente pode exigir atualizações que alterem o estrutura de banco de dados. A ideia é que tudo o que pode ser personalizado, qualquer os requisitos específicos do cliente residirão nessas classes.
  • Haverá relatórios, principalmente envolvendo a extração de registros correspondentes categorias específicas, pesquisas por palavras, etc.

Eu tenho o esquema do banco de dados feito e definido, e a lógica de como tabelas relacionar é claro. Eu usei este mesmo esquema em outro framework, mas um aplicativo baseado na web não parece oferecer o nível de poder ao usuário em relação à GUI, que é essencial para diferenciar este produto dos outros.

Minha pergunta é como criar classes em torno do banco de dados. É importante acertar isso, para que a arquitetura do software não precise ser redesenhado mais tarde. As aulas não serão responsáveis pelo persistente loja, apenas para atuar como intermediário entre a camada responsável pela o armazenamento persistente e os controllers / views.

A abordagem mais lógica parece ser ter uma classe para não conformidades / reclamações etc, que armazenam apenas a instância (ou seja, um objeto por registro de não conformidade), validar dados e lógica de negócios específica da classe (isto é, cálculos ). Uma classe por tabela parece lógica neste caso. O que estou enfrentando é saber se é prática padrão simplesmente ter membros de dados para cada coluna, definir getters e setters ou se devo criar uma classe que não esteja codificada para mapear para uma tabela, mas que preencha um mapa baseado no esquema do banco de dados ou arquivo externo que define as propriedades do banco de dados e da coluna. O primeiro significa que a codificação para a classe precisa ser alterada quando as colunas são modificadas, e o segundo, potencialmente, não. Tenha em mente que, na maior parte do tempo, cada usuário estará trabalhando com um registro de cada vez.

Em suma, eu posso ver o exemplo de como fazer consultas SQL, mas eu tenho lutado para encontre qualquer coisa que me mostre como a turma deve ser (ou se toda essa abordagem está errada) e gostaria de comparar o que estou fazendo, com o que a indústria definiria como boa prática (eu não sou um programador comércio).

Obrigado,

    
por Borax Man 26.09.2014 / 13:56
fonte

4 respostas

1

A primeira pergunta é se você está bem em ter que recompilar o programa toda vez que o esquema do banco de dados mudar. Não estou bem claro na sua situação, mas por exemplo:

Você tem um número de clientes com necessidades ligeiramente diferentes (ou seja, A precisa rastrear as propriedades X, Y, Z, mas B também precisa rastrear a propriedade W), mas para um determinado cliente essas necessidades são bastante constantes. E você pode trabalhar com e implantar um aplicativo personalizado para cada cliente (também conhecido como você não está vendendo isso sozinho). Nesse caso, ter um modelo que você pode herdar e modificar por cliente pode ser uma boa estratégia de negócios, se o número total de clientes não for alto o suficiente para fazer valer a pena criar um aplicativo altamente adaptável desde o início. começar. Tendo 5 versões diferentes do programa ainda é sustentável, 100 não é.

Por outro lado, se você tiver 100 clientes, simplesmente não poderá alterar o código toda vez que um deles quiser adicionar uma propriedade (coluna) a algo. Ou até mesmo adicionar um novo tipo de objeto. Assim, o programa precisará ser mais dinâmico, provavelmente trabalhando em um mapa relacional que seja salvo em algum lugar e que possa ser editado pelo programa conforme necessário.

Então vamos supor que o que você tem é mais parecido com o anterior. Ter turmas que representam os tipos de registros que você tem é uma boa maneira de fazer isso. Essas classes podem conter consultas SQL diretamente. Você ainda deve ter coisas como nomes de tabelas como constantes definidas em um arquivo .h comum e, em seguida, chamá-las como constantes em seu código real, portanto, qualquer alteração precisa ser feita em apenas um lugar. Então, se você precisar de um objeto um pouco diferente para um cliente diferente, poderá herdar as classes que já possui e fazer as alterações necessárias.

Você também pode montar uma classe intermediária que lide com as interações reais do banco de dados, portanto, se você alterar o esquema ou até mesmo o tipo de banco de dados que estiver usando, basta trocar ou modificar essa classe.

    
por 26.09.2014 / 16:02
fonte
1

Eu recomendo ter uma classe por tabela e um campo por coluna. Esse padrão é amplamente usado por Object Relational Mappers (ORMs) em muitos idiomas, e funciona muito bem. Essas classes formam seu modelo de domínio. Um problema, como outros notaram, é que, se você quiser alterar seu esquema de dados, precisará alterar o código do aplicativo. Se isso for um problema para você, convém considerar dados semiestruturados (por exemplo, colunas JSON ou até NoSQL).

Você pode colocar alguma lógica em suas classes de dados, mas eu costumo manter isso bastante leve. E os métodos em uma classe de dados só devem operar nessa classe. Para uma lógica de negócios mais envolvida e qualquer coisa que envolva mais de uma classe, crie uma camada de serviço. A camada de serviço oferece uma API para o restante do seu aplicativo e depende do modelo.

A propósito, é bastante incomum escrever este tipo de software em C ++. Geralmente, linguagens de nível mais alto (C #, Java, Python etc.) são mais adequadas.

    
por 25.11.2014 / 21:02
fonte
0
Primeiro, para mim, a maneira mais natural de abordar projetos como esse é projetar primeiro o modelo de domínio e, depois disso, projetar como esse modelo é implementado na linguagem de programação selecionada ou como é armazenado em um banco de dados relacional.

Em segundo lugar, como cada cliente exigirá emendas, colunas adicionais e nomes de coluna personalizados, eu esqueceria a ideia de armazenar cada registro em uma única linha e, em vez disso, usar o valor de atributo da entidade (EAV) ou até mesmo considerar o uso de um banco de dados orientado a documentos em vez de um relacional. Deve-se notar, porém, que algumas pessoas consideram o modelo EAV como um antipadrão porque causará algumas complexidades adicionais.

Por fim, acredito que todos os registros ainda terão alguns subconjuntos compartilhados de atributos principais iguais para todos os clientes. Para mim, a abordagem mais limpa seria separar essa parte essencial das extensões específicas do cliente. Os principais atributos que eu manteria como membros de dados em suas classes C ++ para facilitar o uso e projetar um mecanismo separado para as extensões. Além disso, se você decidir usar algo como o modelo EAV, ainda manteria esses atributos principais em colunas dedicadas em vez de dividi-los em suas próprias linhas.

    
por 26.10.2014 / 17:58
fonte
0

O erro comum que muitas pessoas cometem com o mapeamento de banco de dados é que elas se concentram no esquema e desenvolvem uma representação strongmente acoplada das tabelas nas classes de lógica de negócios. Esta não é a melhor maneira - obviamente, isso torna a camada de lógica de negócios tão strongmente acoplada ao banco de dados que eles rapidamente percebem que é um erro e acabam adicionando outra camada para tentar desacoplar a lógica de negócios do banco de dados, chamando-a de DAO ou ORM. ou similar.

O que você deve fazer é olhar para o seu banco de dados como uma camada em si, que fornece uma API onde as solicitações de dados são feitas. Acho mais fácil conceituar isso escrevendo todo o seu SQL como procedimentos armazenados e restringindo todo o acesso às tabelas subjacentes. (esta abordagem também tem o benefício de aumentar a segurança)

Depois de fazer isso, você começa a examinar os dados como um recurso a ser consumido, a lógica de negócios terá classes escritas nesse mapa para os procedimentos armazenados e eles trabalham juntos - lógica nas classes de lógica de negócios com dados que são operado de acordo com sua "API de dados". Isso também significa que você pode alterar o esquema sem qualquer alteração na camada de lógica de negócios (embora, obviamente, se você alterar a API do proc armazenado, será necessário alterar os chamadores, mas poderá adicionar novos sprocs onde necessário sem qualquer impacto no código existente).

Outro benefício é que seu banco de dados e sua lógica de negócios são independentes e podem ser trabalhados separadamente. usar sua API do DB não seria muito diferente de usar uma API de terceiros fornecida por meio de um serviço da Web ou outra fonte de dados.

    
por 26.11.2014 / 10:21
fonte