Separación de recuperación de datos y objetos comerciales entre capas DAL y BLL

9

Investigué un poco antes de publicar esta pregunta. Entre otras preguntas o publicaciones, una de ellas se proporciona a continuación. No pude tener una idea clara de cómo determinar ...

Business Objects dentro de una capa de acceso a datos

Tengo un repositorio y Business Layers llama al repositorio para recuperar los datos. Por ejemplo, supongamos que tengo las siguientes clases para BLL y 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; }
}

Si el BLL desea recuperar un objeto Cliente, llamaría a GetCustomerById (customerId) en DAL.

Las siguientes son mis preocupaciones, no pude tener una mente clara:

  1. No puedo ver cómo determinar qué objeto debe devolver el GetCustomerById en DAL. ¿Debería devolver BllCustomer o DalCustomer?

  2. ¿Dónde debería estar la recuperación (y / o conversión a objeto comercial) de la dirección asociada con el cliente?

Si el DAL devuelve objetos Dal, entonces, la lógica para recuperar y completar la Dirección solo puede estar en el BLL. Si el DAL devuelve objetos BLL, entonces la lógica para recuperar y completar la Dirección puede estar en BLL o DAL. Actualmente, el DAL está devolviendo los Business Objects y la lógica para completarlo está en el DAL.

Por lo que leí, supongo que no hay correcto o incorrecto. Desde el enlace incluido anteriormente, hay personas que dicen de una manera y las otras dicen lo contrario. Pero, ¿cómo determino cuál funcionaría mejor para mi caso?

Cualquier ayuda sería apreciada.

ShamirDaj
fuente
2
Mi primera pregunta sería: ¿es esta una aplicación heredada? Hay un montón de marcos ORM por ahí que hacen que este tipo de código obsoleto y yo le pido a considerar un marco de este tipo ...
JDT
@JDT No estoy seguro de lo que quieres decir, estoy usando Entity Framework y tengo exactamente el mismo problema. Según tengo entendido, no se supone que use su ORM como objetos de dominio, entonces, ¿dónde se realiza la traducción?
pseudocoder
¿Por qué su marco ORM no devolvería objetos que también son objetos de dominio?
JDT
3
@JDT El ORM (EF en este caso) devuelve clases de entidad que representan, típicamente, una tabla de base de datos por clase. Esto suele ser similar a las clases de dominio, pero no necesariamente lo mismo. ¿Quizás solo estás diciendo que está bien usar las clases ORM como clases de dominio? He leído en varios lugares que esto es un no-no.
pseudocoder

Respuestas:

5

No puedo ver cómo determinar qué objeto debe devolver el GetCustomerById en DAL. ¿Debería devolver BllCustomer o DalCustomer?

Debería devolver un objeto DalCustomer , devolver un objeto BllCustomer romperá el principio de responsabilidad única . Puede ver el objeto DalCustomer como la interfaz o contrato consumido por la capa empresarial (o consumidor). En efecto, si devuelve un BllCustomer, el DAL tendría que atender a cada objeto de la capa empresarial que lo llama o podría llamarlo.

¿Dónde debería estar la recuperación (y / o conversión a objeto comercial) de la dirección asociada con el cliente?

La conversión debe hacerse en un modelo de vista o administrador. Debe tener un intermediario para llamar a su servicio o componente de acceso a datos. Si siente la necesidad, puede tener una conversión en su objeto BllCustomer . Pero luego, cuando cambia su DAL de MSSQL a Oracle, por ejemplo, su objeto (o interfaz) devuelto debe permanecer igual.

Preferiblemente, su capa empresarial también debe ser independiente de su capa de datos. La capa empresarial es responsable de sus reglas comerciales. Es aquí donde agregará sus validaciones utilizando un marco de validación para hacer cumplir sus reglas comerciales.

Derika
fuente
4

Su repositorio debe devolver el BLL o el objeto de dominio. es probable que no necesite un objeto DAL en absoluto.

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
fuente
¿Debería BLL o una biblioteca de clases separada exponer interfaces en lugar de clases concretas Customer?
Yola
1
No. Está bien exponer clases concretas. Sería útil una interfaz para el repositorio
Ewan
3

Típicamente, el DAL no tiene conocimiento del BLL. Piénselo de esta manera, una aplicación diferente con un BLL diferente podría usar el mismo DAL. Una aplicación / módulo Payables y una aplicación Receivables para la misma compañía compartirían datos (clientes, cargos, pagos, etc.). Intentar tener una DLL con conocimiento de más de una BLL sería muy difícil e innecesario. Esto también le permitiría cambiar su almacenamiento de datos sin impacto en el BLL (siempre que no rompa las interfaces).

Ahora puede pasar un objeto DAL al BLL o puede crear un tercer conjunto de objetos: Entidad. Estos contendrían solo los valores que se pasarían juntos. El DAL haría referencia a la entidad e interactuaría con su almacenamiento / base de datos y el BLL manejaría toda la lógica y haría referencia al 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
fuente
Gracias por tu comentario. Estoy de acuerdo con usted ... Ya puedo ver que nuestro DAL / (Repositorio) ya está lleno de lógicas como si el tipo es A, luego vaya a recuperar datos de la tabla B, pero si el tipo es C, vaya a recuperar datos de la tabla C. Pero estoy confundido con su ejemplo usando EntCustomer. En mi caso, DalCustomer es espejo de las tablas en DB. ¿Puede proporcionar más ejemplos, cómo se usa el EntCustomer o por qué debería usarlo y los beneficios de esto? Estoy pensando en cambiar DAL para devolver DalObjects al BLL. Bll bloqueará la conversión a Business Objs, recuperará y completará obj anidado.
ShamirDaj
¿Puedes darnos más comentarios?
ShamirDaj
Creo que el propósito de los objetos Ent es simplemente transferir datos entre DAL y BLL. Sus clases de DAL pueden continuar reflejando la estructura de db, pero esas clases serían internas a DAL. Cuando el BLL solicita datos de DAL, el DAL buscaría los objetos DAL requeridos de la base de datos (dalcustomer + daladdress) y construiría una instancia de EntCustomer de ellos y los devolvería a BLL.
artokai
-1

DAL debe ser independiente de BL y BL depende de DAL. Su interfaz de usuario solo debe acceder a los datos a través de BL. Es una buena práctica si devuelve DataTable o DataRow desde DAL y luego convierte DataTable / DataRow en objetos BL. Cuando su IU necesita acceder a los datos, puede acceder desde BL. Por lo tanto, la interfaz de usuario será independiente del nombre de la columna y el tipo de base de datos (SQL Server, Oracle ...). De esta manera, su interfaz de usuario será totalmente independiente de DAL. Personalmente, prefiero el nombre de la clase como "CustomerBL". No use la palabra BL al principio del nombre de la clase.

A continuación, ver Código de muestra.

//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
fuente
Err ... ¿No significa eso que su BLL necesita tener conocimiento del formato / estructura de sus tablas de datos? ...
Paul