Aplicativo de banco de dados com N camadas sem usar um ORM, como a interface do usuário especifica o que precisa dos dados a serem exibidos?

Eu estou procurando por ponteiros e informações aqui, eu vou fazer este CW desde que eu suspeito que não tem uma única resposta correta. Isso é para C #, portanto, farei algumas referências ao Linq abaixo. Eu também peço desculpas pelo longo post. Deixe-me resumir a questão aqui e, em seguida, a pergunta completa segue.

Resumo: Em um aplicativo de 4 camadas UI / BLL / DAL / DB, como as alterações na interface do usuário, para mostrar mais colunas (digamos, em uma grade), evitam vazamento na camada de lógica de negócios e na camada de acesso a dados. se apossar dos dados para exibir (supondo que já está no banco de dados).

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

Interface do usuário (UI)Camada lógica de negócios (BLL)Camada de acesso a dados (DAL)Banco de dados (DB; a quarta camada)

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

É a única maneira de "corretamente" construir tal camada para sempre fazer "select *"? 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 possuem um registro de emprego ativo. Por "ativo" quero dizer que os registros de emprego de até-datas contém hoje (ou talvez até mesmo uma data que eu possa definir na interface do usuário).

Neste caso, digamos que eu queira enviar um e-mail para todas essas pessoas, então eu tenho um código na BLL que garante que eu não enviei e-mails para as mesmas pessoas, etc.

Para a BLL, ela precisa de quantidades mínimas de dados. Talvez ele chame a camada de acesso a dados para obter essa lista de funcionários ativos e, em seguida, uma chamada para obter uma lista dos e-mails enviados. Em seguida, ele se une a eles 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, não há realmente muitos dados de que ela precisa. Talvez seja necessário apenas que o identificador exclusivo de cada funcionário, para ambas as listas, corresponda e, em seguida, diga "Esses são os identificadores exclusivos daqueles que estão ativos, para os quais você ainda não enviou um e-mail". Então, eu construo o código DAL que constrói instruções SQL que apenas recuperam o que a camada de negócios precisa? Ie. apenas "SELECT id FROM employees WHERE ..."?

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 daporque Eu quero enviar e-mails. Por exemplo, talvez eu queira incluir algumas informações de contato rudimentares, ou o departamento para o qual eles trabalham, ou o nome de seus gerentes, etc., para não dizer que eu pelo menos nomeia e informações de endereço de e-mail para mostrar.

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

E então, quando a interface do usuário é alterada, para ajudar ainda mais o usuário, adicionando mais colunas, qual seria o nível de profundidade necessário para alterar a interface do usuário? (supondo que os dados estejam presentes no banco de dados já, portanto, nenhuma mudança é necessária lá.)

Uma sugestão é usar o Linq-To-SQL e o IQueryable, de modo que, se o DAL lida com o que (como em quais tipos de dados) e por que (como nas cláusulas WHERE) retornou o IQueryables, a BLL poderia potencialmente retornam esses valores para a UI, que poderia então construir uma consulta Linq que recuperaria os dados necessários. O código da interface do usuário pode, então, inserir as colunas necessárias. Isso funcionaria, uma vez que com o IQuerables, a UI acabaria realmente executando a consulta e poderia usar "select new {X, Y, Z}" para especificar o que ela precisa, e até se juntar a 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 por trás de um frontend Linq.

Mas, para que isso aconteça, a BLL ou o DAL não devem ter permissão para fechar as conexões do banco de dados, e em um tipo de mundo IoC, o serviço DAL pode ser descartado um pouco antes do código da interface do usuário. A consulta Linq pode acabar com a exceção "Não é possível acessar um objeto descartado".

Então estou procurando por ponteiros. Quão longe estamos? Como você está lidando com isso? Eu considero o fato de que as mudanças na interface do usuário vão vazar através da 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 provamos que estou errado?

E note que este é um sistema legado. Alterar o esquema do banco de dados não está no escopo por anos ainda, portanto, uma solução para usar objetos ORM que essencialmente fariam o equivalente a "select *" não é realmente uma opção. Temos algumas tabelas grandes que gostaríamos de evitar percorrer toda a lista de camadas.

questionAnswers(2)

yourAnswerToTheQuestion