Então, eu tenho criado uma camada de acesso a dados via TDD e me aproximei de alguma preocupação. Prefiro não seguir o caminho errado, então imaginei pedir a vocês para ver se meus pensamentos estavam alinhados com uma arquitetura limpa.
Os métodos dentro da minha camada de acesso a dados (DAL) são bastante simples. Eles estão alinhados com os procedimentos armazenados no banco de dados (não há outra maneira de entrar nele para manter as coisas limpas) e contêm os mesmos parâmetros que os procedimentos. Eles então se conectam ao banco de dados e retornam o resultado da consulta. Aqui está um exemplo:
public int DeleteRecord(int recordId)
{
recordId.RequireThat("recordId").NotZeroOrLess();
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter { ParameterName = "@RecordId", SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Input, Value = recordId});
return this.ExecuteNonQuery("DeleteRecord", parameters.ToArray());
}
Isso funciona perfeitamente para esse tipo de método porque não estou fazendo nada significativo com o conjunto de resultados. Eu só quero ter certeza de que o comando funcionou, então retornarei o resultado da não consulta, que é apenas as linhas afetadas, e posso verificar a lógica usando esse número.
No entanto, digamos que em outro método DAL, desejo carregar um registro. Meu procedimento de carregamento será executado selects
em várias tabelas e retornará a DataSet
, mas estou discutindo se meu DAL deve criar os Objetos de Negócios dentro do método usando o DataSet
, ou se meus próprios Objetos de Negócios devem ter apenas um Load()
método que obtenha o DataSet
do DAL e, em seguida, se preenche basicamente.
Fazer isso através do DAL resultaria em menos lógica nos Objetos de Negócios (mesmo sendo apenas lógica de seleção, ainda é lógica), mas aglomeraria o DAL um pouco e faria parecer que realmente está fazendo algo que não deveria ' Não estou fazendo.
O que é que vocês acham?
Respostas:
Seu DAL deve retornar seus objetos de dados
Idealmente, o seu DAL deve ser um objeto de "caixa preta", que o código do aplicativo pode usar para solicitar um objeto de dados ou manipular objetos de dados existentes. Às vezes, há outra camada colocada entre o DAL e o código do aplicativo chamado the
Repository
, que separa ainda mais as duas camadas, embora isso nem sempre seja necessário.Além disso, você geralmente não deseja que seus objetos de negócios possam se criar. Isso pode causar falhas de segurança nas quais alguém pode usar sua biblioteca e criar uma nova instância do seu objeto chamando
.Load(someId)
-o, e ele mescla duas camadas que devem ser completamente separadas.Também não recomendo fornecer um
.Load(DataSet ds)
método porque, se a definição do conjunto de dados for alterada, você terá que caçar os objetos de dados que usam esse conjunto de dados e alterá-los. É mais fácil manter todo o seu código de acesso a dados em um único local; portanto, se você alterar a consulta de acesso a dados, precisará alterar apenas sua camada DAL.fonte
BusinessObject bo = DAL.LoadRecord(id);
- parece certo? A lógica para mapear a consulta para o próprio BO estaria contida no DAL e somente lá.Get
vez deLoad
, comoCustomer c = DAL.GetCustomer(id);
Meu método, mesmo antes do LINQ-To-SQL e do Entity Framework, era ter uma interface e uma biblioteca de classes abstratas que forneciam um "contrato por escrito" para a comunicação entre as diferentes camadas do aplicativo. Isso às vezes é chamado de ontologia , uma definição para um domínio de trabalho. Qualquer coisa que passasse entre as camadas usava esse 'contrato'.
Não gosto da ideia de passar objetos brutos do conjunto de dados da camada de dados para a camada comercial. Eu já vi esse resultado em vários problemas, especialmente ao integrar fontes de dados herdadas. Também pode tornar muito difícil para as novas pessoas que entram em um projeto entender de onde vêm os dados. Por fim, exige que sua camada de negócios esteja no negócio de manipular dados diretamente do banco de dados, o que pode levar a complicações no futuro.
O código de exemplo que você tinha se parece com o código que eu tinha antes do LINQ. Eu tinha uma classe de função de banco de dados comum que usei dentro dos meus objetos DAL. As classes DAL liam os dados e os encaixavam nos objetos 'contract'. Resultados escalares, como o seu exemplo de exclusão, retornariam um valor, geralmente um valor booleano.
fonte
ExecuteScalar
consultas para retornar valores que fazem mais sentido para uma camada de negócios, comobool
? Penso de outra forma, esta é uma resposta muito semelhante à de Rachel.Seu DAL deve retornar um conjunto de dados. Esse conjunto de dados retornado deve ser o objeto de negócio, não deve haver nada que você precise fazer além de verificar se possui os dados esperados. Se você precisar fazer mais com ele, tente fazer demais em um único procedimento armazenado ou não retorne os dados corretamente no procedimento armazenado.
fonte
Eu recomendo que seus objetos de negócios tenham um construtor para preencher a partir de um conjunto de resultados. Isso remove o acoplamento entre seu DAL e a camada de negócios. Se você deseja isolar completamente os dois, crie um mapa simples dos pares nome da coluna => valor do seu conjunto de resultados e passe-o para o construtor.
fonte