Aplicativo de banco de dados em camada N sem usar um ORM, como a interface do usuário especifica o que precisa dos dados para exibir?

StackOverflow https://stackoverflow.com/questions/1524367

Pergunta

Estou procurando ponteiros e informações aqui, farei essa CW, já que suspeito que não tenha uma resposta correta. Isto é para C#, portanto, farei algumas referências ao LINQ abaixo. Também peço desculpas pelo longo post. Deixe -me resumir a pergunta aqui e depois a pergunta completa segue.

Resumo: Em um aplicativo UI/BLL/DAL/DB de 4 camadas, como as mudanças na interface do usuário, para mostrar mais colunas (digamos em uma grade), evite vazar através da camada lógica de negócios e entrar na camada de acesso a dados, para Consiga os dados a serem exibidos (assumindo que já está no banco de dados).


Vamos supor um aplicativo em camadas com 3 (4) camadas:

  • Interface do usuário (interface do usuário)
  • Camada lógica de negócios (BLL)
  • Camada de acesso a dados (DAL)
  • Banco de dados (db; a 4ª camada)

Nesse caso, o DAL é responsável por construir instruções SQL e executá -las no banco de dados, retornando os dados.

A única maneira de "corretamente" construir essa camada para fazer sempre "selecionar *"? Para mim, isso é um grande não-não, mas deixe-me explicar por que estou me perguntando.

Digamos que eu queira, para minha interface do usuário, exibir todos os funcionários que têm um registro de emprego ativo. Por "ativo", quero dizer que os registros de emprego de datas contêm hoje (ou talvez até uma data que eu possa definir na interface do usuário).

Nesse caso, digamos que eu queira enviar um e -mail para todas essas pessoas, por isso tenho algum código no BLL que garante que ainda não enviei e -mail para as mesmas pessoas, etc.

Para o BLL, ele precisa de quantidades mínimas de dados. Talvez ele chame a camada de acesso a dados para obter a lista de funcionários ativos e, em seguida, uma chamada para obter uma lista dos e -mails que ela enviou. Em seguida, ele se junta a esses e constrói uma nova lista. Talvez isso possa ser feito com a ajuda da camada de acesso a dados, isso não é importante.

O importante é que, para a camada de negócios, realmente não há muitos dados necessários. Talvez ele precise apenas do identificador exclusivo para cada funcionário, para ambas as listas, para combinar e, em seguida, diga "esses são os identificadores exclusivos daqueles que estão ativos, que você ainda não enviou um email para". Construo o código DAL que constrói instruções SQL que apenas recuperam o que a camada de negócios precisa? Ou seja. Basta "selecionar ID dos funcionários onde ..."?

O que eu faço então para a interface do usuário? Para o usuário, talvez seja melhor incluir muito mais informações, dependendo de Por quê Eu quero enviar e -mails. Por exemplo, posso querer incluir algumas informações de contato rudimentares, ou o departamento para o qual trabalham, ou o nome de seus gerentes, etc., para não dizer que pelo menos o nome e as informações do endereço de e -mail para mostrar.

Como a interface do usuário obtém esses dados? Eu altero o DAL para garantir que eu retorne dados suficientes para a interface do usuário? Eu altero o BLL para garantir que ele retorne dados suficientes para a interface do usuário? Se o objeto ou as estruturas de dados retornadas do DAL de volta ao BLL também poderão ser enviadas para a interface do usuário, talvez o BLL não precise de muita mudança, mas os requisitos da interface do usuário afetam uma camada além do que deve se comunicar com . E se os dois mundos operassem em diferentes estruturas de dados, as mudanças provavelmente teriam que ser feitas para ambas.

E o que então, quando a interface do usuário é alterada, para ajudar o usuário ainda mais, adicionando mais colunas, quão profundo seria/devo ir para alterar a interface do usuário? (Supondo que os dados já estejam presentes no banco de dados, para que nenhuma alteração seja necessária lá.)

Uma sugestão que surgiu é usar o LINQ-para-SQL e o IQueryable, de modo que, se o dal, que lida com o que (como em que tipos de dados) e por que (como em onde as cláusulas) retornaram iQueryables, o BLL poderia Potencialmente retornam aqueles à interface do usuário, que poderiam construir uma margem LINQ que recuperaria os dados necessários. O código da interface do usuário pode então puxar as colunas necessárias. Isso funcionaria, pois com os iQuerables, a interface do usuário acabaria realmente executando a consulta e, então, poderia usar "Selecionar novo {x, y, z}" para especificar o que precisa e até participar de outras tabelas, se necessário.

Isso parece confuso para mim. Que a interface do usuário executa o próprio código SQL, mesmo que tenha sido escondido atrás de um front -end LINQ.

Mas, para que isso aconteça, o BLL ou o DAL não deve fechar as conexões do banco de dados e, em um tipo de mundo do COI, o serviço DAL pode ser descartado um pouco mais cedo do que o código da UI gostaria, para que A consulta LINQ pode acabar com a exceção "não pode acessar um objeto descartado".

Então, estou procurando dicas. Quão longe estamos? Como você está lidando com isso? Considero o fato de que as mudanças na interface do usuário vazarão através do BLL e no DAL é uma solução muito ruim, mas agora não parece que podemos fazer melhor.

Por favor, diga -me como somos estúpidos e prove que eu estou errado?

E observe que este é um sistema herdado. Alterar o esquema de banco de dados ainda não está no escopo há anos, portanto, uma solução para usar objetos ORM que faria essencialmente o equivalente a "select *" não é realmente uma opção. Temos algumas mesas grandes que gostaríamos de evitar puxar para toda a lista de camadas.

Foi útil?

Solução

Use o conceito de um modelo de visualização (ou objetos de transferência de dados) que são casos de consumo de interface do usuário. Será o trabalho do BLL para pegar esses objetos e, se os dados estiverem incompletos, solicite dados adicionais (que chamamos de modelo). Em seguida, o BLL pode tomar decisões corretas sobre quais modelos de exibição retornar. Não deixe que o seu modelo (dados) especificamente permeize a interface do usuário.

UI <-- (viewmodel) ---> BLL <-- (model) --> Peristence/Data layers

Este desacoplamento permite aumentar melhor o seu aplicativo. A independência da persistência que eu acho naturalmente sai dessa abordagem, pois a construção e a especificação dos modelos de visualização podem ser feitas de maneira flexível no BLL usando o LINQ2QL ou outra tecnologia ORM.

Outras dicas

Isso não é um problema fácil de resolver. Eu já vi muitas tentativas (incluindo a abordagem iQueryable que você descreve), mas nenhuma que seja perfeita. Infelizmente, ainda estamos esperando a solução perfeita. Até então, teremos que nos contentar com a imperfeição.

Concordo plenamente que as preocupações de DAL não devem vazar até as camadas superiores, portanto, é necessário um BLL isolante.

Mesmo se você não tiver o luxo de redefinir a tecnologia de acesso a dados em seu projeto atual, ele ainda ajuda a pensar no modelo de domínio em termos de ignorância de persistência. Um corolário da ignorância de persistência é que cada objeto de domínio é uma unidade independente que não possui noção de coisas como colunas de banco de dados. É melhor aplicar a integração de dados como invariantes nesses objetos, mas isso também significa que um objeto de domínio instanciado terá todos os seus dados constituintes carregados. É uma proposta de ou seja, portanto, a chave é encontrar um bom modelo de domínio que garante que cada objeto de domínio mantenha (e deve ser carregado com) uma quantidade 'apropriada' de dados.

Objetos muito granulares podem levar a interfaces falsificadas, mas objetos de granulação grossa demais podem levar a muitos dados irrelevantes que estão sendo carregados.

Um exercício muito importante é analisar e modelar corretamente os agregados do modelo de domínio, para que eles atinjam o equilíbrio certo. O livro Design orientado a domínio Contém algumas análises muito esclarecedoras de agregados de modelagem.

Outra estratégia que pode ser útil a esse respeito é o objetivo de aplicar o princípio de Hollywood o máximo possível. O principal problema que você descreve as preocupações, mas se você puder mudar seu foco para ser mais orientado para o comando, poderá definir algumas interfaces mais grossas que não exigir Você sempre carrega muitos dados.

Não estou ciente de nenhuma solução simples para esse desafio. Existem técnicas como as que descrevi acima que podem ajudá -lo a resolver alguns dos problemas, mas no final ainda é uma arte que requer experiência, habilidade e disciplina.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top