Separação da recuperação de dados e objetos de negócios entre as camadas DAL e BLL

9

Eu fiz algumas pesquisas antes de postar esta pergunta. Entre outras perguntas ou postagem, uma delas é fornecida abaixo. Eu não conseguia ter uma mente clara como determinar ..

Objetos de negócios em uma camada de acesso a dados

Eu tenho um repositório e as camadas de negócios chamam o repositório para recuperar os dados. Por exemplo, digamos que eu tenha as seguintes classes para BLL e DAL:

class BllCustomer
{
    public int CustomerId {get; set;}
    public String Name {get; set;}
    public BllAddress Address {get; set;}
}

class BllAddress
{
     public int AddressId {get; set;}
     public String Street {get; set;}
     public String City {get; set;}
     public String ZipCode {get; set; }
}

class DalCustomer 
{
    public int CustomerId {get; set;}
    public String Name {get; set;}
    public int AddressID {get; set;}
}

class DalAddress
{
     public int AddressId {get; set;}
     public String Street {get; set;}
     public String City {get; set;}
     public String ZipCode {get; set; }
}

Se o BLL quiser recuperar um objeto Customer, ele chamaria GetCustomerById (customerId) no DAL.

A seguir, minhas preocupações: não conseguia ter uma mente clara:

  1. Não consigo ver como determinar qual objeto o GetCustomerById no DAL deve retornar? Ele deve retornar BllCustomer ou DalCustomer?

  2. Onde deve estar a recuperação (e / ou a conversão para objeto de negócios) do endereço associado ao cliente?

Se o DAL retornar objetos Dal, a lógica para recuperar e preencher o Endereço poderá estar apenas no BLL. Se o DAL retornar objetos BLL, a lógica para recuperar e preencher o Endereço poderá estar no BLL ou no DAL. Atualmente, o DAL está retornando os Objetos de Negócios e a lógica para preenchê-lo está no DAL.

Pelo que li, acho que não há certo ou errado. No link incluído acima, há pessoas dizendo uma maneira e as outras estão dizendo a outra maneira. Mas como determino qual funcionaria melhor para o meu caso?

Qualquer ajuda seria apreciada.

ShamirDaj
fonte
2
Minha primeira pergunta seria: esse é um aplicativo herdado? Há uma abundância de ORM Frameworks lá fora que fazem este tipo de código obsoleto e exorto-vos a considerar esse quadro ...
JDT
@JDT Não sei bem o que você quer dizer, estou usando o Entity Framework e tendo exatamente o mesmo problema. Pelo que entendi, você não deveria usar seu ORM como objetos de domínio; então, onde é feita a tradução?
Pseudocoder
Por que sua estrutura ORM não retornaria objetos que também são objetos de domínio?
JDT
3
@JDT O ORM (neste caso, EF) retorna classes de entidade que representam, normalmente, uma tabela de banco de dados por classe. Isso geralmente é semelhante, mas não necessariamente o mesmo, às classes de domínio. Talvez você esteja apenas dizendo que não há problema em usar classes ORM como classes de domínio? Eu li em vários lugares que isso é um não-não.
Pseudocoder

Respostas:

5

Não consigo ver como determinar qual objeto o GetCustomerById no DAL deve retornar? Ele deve retornar BllCustomer ou DalCustomer?

Ele deve retornar um objeto DalCustomer , retornar um objeto BllCustomer violará o princípio de responsabilidade única . Você pode visualizar o objeto DalCustomer como a interface ou contrato consumido pela camada de negócios (ou consumidor). De fato, se ele retornasse um BllCustomer, o DAL precisaria atender a todos os objetos da camada de negócios que o chamam ou poderiam potencialmente chamá-lo.

Onde deve estar a recuperação (e / ou a conversão para objeto de negócios) do endereço associado ao cliente?

A conversão deve ser feita em um modelo ou gerente de exibição . Você precisa de um intermediário para ligar para o seu serviço ou componente de acesso a dados. Se você sentir necessidade, poderá fazer uma conversão no seu objeto BllCustomer . Mas quando você troca seu DAL do MSSQL para Oracle, por exemplo, seu objeto (ou interface) retornado deve permanecer o mesmo.

De preferência, sua camada de negócios também deve ser independente da sua camada de dados. A camada de negócios é responsável por suas regras de negócios. É aqui que você adicionará suas validações usando uma estrutura de validação para impor suas regras de negócios.

Derika
fonte
4

Seu repositório deve retornar o BLL ou objeto de domínio. é provável que você não precise de um objeto DAL.

public class Customer
{
    public string Name {get; private set;}
    public Customer(string name)
    {
        this.Name = name;
    }
}

public class Repository
{
    public Customer GetCustomer(string id)
    {
        //get data from db
        return new Customer(datarow["name"]);
    }
}
Ewan
fonte
BLL ou biblioteca de classes separada deve expor interfaces em vez de classes concretas como Customer?
Yola
11
Não. É bom expor classes concretas. Uma interface para o repositório seria útil
Ewan
3

Normalmente, o DAL não tem conhecimento do BLL. Pense dessa maneira: um aplicativo diferente com um BLL diferente poderia usar o mesmo DAL. Um aplicativo / módulo de Contas a pagar e um aplicativo de Contas a receber da mesma empresa compartilhariam dados (clientes, cobranças, pagamentos etc.). Tentar ter uma DLL com conhecimento de mais de uma BLL seria muito difícil e desnecessário. Isso também permitiria alterar seu armazenamento de dados sem afetar o BLL (desde que você não quebre as interfaces).

Agora você pode passar um objeto DAL para o BLL ou criar um terceiro conjunto de objetos: Entidade. Estes conteriam apenas os valores a serem passados ​​juntos. O DAL referenciaria a entidade e interagia com seu armazenamento / banco de dados e o BLL lidaria com toda a lógica e referenciaria o DAL.

class EntCustomer
{
    public int CustomerId {get; set;}
    public String Name {get; set;}
    public BllAddress Address {get; set;}
}
class BllCustomer
{
   //reference EntCustomer, DalCustomer and handle business rules/logic
}

class DalCustomer 
{
   //reference EntCustomer and interact with data storage
}
JeffO
fonte
Obrigado pelo seu comentário. Eu concordo com você .. Eu já posso ver que nosso DAL / (Repositório) já está cheio de lógicas como se o tipo é A, em seguida, recupere os dados da tabela B, mas se o tipo for C, recupere os dados da tabela C. Mas estou confuso com o seu exemplo usando o EntCustomer. No meu caso, o DalCustomer é espelho das tabelas no DB. Você pode fornecer mais exemplos, como o EntCustomer é usado ou por que eu deveria usá-lo e os benefícios dele. Estou pensando em alterar o DAL para retornar o DalObjects para o BLL. O Bll suspenderá a conversão em Objetos de Negócios, recuperará e preencherá objetos aninhados.
perfil completo de ShamirDaj
Você pode fornecer mais feedback?
precisa saber é o seguinte
Eu acho que o objetivo dos objetos Ent é apenas transferir dados entre DAL e BLL. Suas classes DAL podem continuar espelhando a estrutura db, mas essas classes seriam internas ao DAL. Quando o BLL solicita dados do DAL, o DAL busca os objetos DAL necessários no banco de dados (dalcustomer + daladdress) e constrói uma instância do EntCustomer a partir deles e os devolve ao BLL.
Artokai #
-1

O DAL deve ser independente do BL e o BL depende do DAL. Sua interface do usuário deve acessar apenas dados via BL. É uma boa prática se você retornar DataTable ou DataRow do DAL e depois converter DataTable / DataRow em objeto (s) BL. Quando sua interface do usuário precisa acessar os dados, ela pode acessar do BL. Portanto, a interface do usuário será independente do nome da coluna e do tipo de banco de dados (SQL Server, Oracle ..). Dessa forma, sua interface do usuário será totalmente independente do DAL. Pessoalmente, prefiro o nome da classe como "CustomerBL". Não use a palavra BL no início do nome da classe.

Veja abaixo o código de exemplo.

//Customer Class
class BllCustomer
{
    public int CustomerId { get; set; }
    public String Name { get; set; }
    public BllAddress Address { get; set; }

    public static BllCustomer GetByCustomerId(int id)
    {
        DataRow dr = DalCustomer.GetByCustomerId(id);
        if (dr == null)
            return null;
        BllCustomer oCust = new BllCustomer();
        oCust.CustomerId = int.Parse(dr["CustomerId"].ToString());
        //Do for other class members and load values

        return oCust;
    }
}


class DalCustomer
{

    public static DataRow GetByCustomerId(int id)
    {
        //Get Data row from Database and return Datarow
        DataRow CustomerRow = GETFROMDATABASE("SELECT * from CUSTOMER");
        return CustomerRow;
    }
}
Jigneshk
fonte
Err ... Isso não quer dizer então que o seu BLL precisa ter conhecimento do formato / estrutura de suas tabelas de dados ...?
Paul