Business Objects dentro de una capa de acceso a datos

12

Así que he estado creando una capa de acceso a datos a través de TDD y me he acercado a una preocupación. Prefiero no comenzar por el camino equivocado, así que pensé en pedirles que vean si mis pensamientos están en línea con una arquitectura limpia.

Los métodos dentro de mi capa de acceso a datos (DAL para abreviar) son bastante simples. Están en línea con los procedimientos almacenados en la base de datos (no hay otra forma de invocarla para mantener las cosas limpias) y contienen los mismos parámetros que los procedimientos. Luego simplemente se conectan a la base de datos y devuelven el resultado de la consulta. Aquí hay un ejemplo:

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());
}

Esto funciona perfectamente para este tipo de método porque no estoy haciendo nada significativo con el conjunto de resultados. Solo quiero asegurarme de que el comando funcionó, por lo que devolveré el resultado de la no consulta, que son solo las filas afectadas, y puedo verificar la lógica usando ese número.

Sin embargo, digamos en otro método DAL, quiero cargar un registro. Mi procedimiento de carga se ejecutará selectsen un montón de tablas y devolverá un DataSet, pero estoy luchando con si mi DAL debería crear los Business Objects dentro del método usando el DataSet, o si mis Business Objects deberían tener un Load()método que obtenga el DataSetdesde el DAL, y luego básicamente se completa.

Hacerlo a través del DAL resultaría en menos lógica en los Business Objects (aunque esto es solo lógica selecta, sigue siendo lógica), pero saturaría un poco el DAL y haría sentir que realmente está haciendo algo que no debería ' No estaré haciendo.

¿Qué piensan ustedes?


fuente
¿Por qué no usaste Entity Framework?
jfrankcarr
@jfrankcarr - Para ser honesto, principalmente porque no estoy tan familiarizado con él como debería estarlo. Sin embargo, necesitaría volver a trabajar mis tablas y agregar las claves foráneas adecuadas, etc. para que Entity Framework reconozca las relaciones correctamente. Sin embargo, solo por curiosidad, si lo estuviera usando, ¿haría toda la selección usando el marco con los Business Objects mismos, o aún habría una decisión sobre dónde colocar esas consultas LINQ?
Recomiendo tomarse el tiempo para aprender EF. Puede parecer un poco desalentador al principio, especialmente cuando se trata de que se ajuste a una base de datos existente que tiene algunos problemas de diseño preexistentes, pero vale la pena.
jfrankcarr
También puede mirar NHibernate si desea buscar otra opción.
Don 01001100
@jfrankcarr: definitivamente lo investigaré, pero ¿cómo encaja con una aplicación de acceso a datos de varios niveles? ¿Se implementaría el propio marco de la entidad dentro del DAL mismo, o dentro de otra capa o incluso los Business Objects mismos?

Respuestas:

4

Su DAL debe devolver sus objetos de datos

Idealmente, su DAL debe ser un objeto de "recuadro negro", que el código de su aplicación puede usar para solicitar un objeto de datos o manipular objetos de datos existentes. A veces hay otra capa entre el DAL y el código de la aplicación llamada Repository, que separa aún más las dos capas, aunque esto no siempre es necesario.

Además, por lo general, no desea que sus objetos comerciales puedan crearse ellos mismos. Esto puede causar agujeros de seguridad en los que alguien puede usar su biblioteca y crear una nueva instancia de su objeto al invocarlo .Load(someId), y fusiona dos capas que deberían estar completamente separadas.

Tampoco recomiendo proporcionar un .Load(DataSet ds)método porque si cambia la definición del conjunto de datos, tendrá que buscar los objetos de datos que usan ese conjunto de datos y cambiarlos. Es más fácil mantener todo su código de acceso a datos en un solo lugar, por lo que si cambia la consulta de acceso a datos, solo debería cambiar su capa DAL.

Rachel
fuente
No estoy seguro de cómo se puede depender de una capa para "devolver el objeto correcto" si la definición de "objeto correcto" se mantiene en otra capa.
TMN
@ TMN Eso estaba mal redactado. Cambié un poco la redacción porque tienes razón, el código de la aplicación debe saber qué tipo de objeto está pidiendo.
Rachel
@Rachel - Gotcha. Entonces, recomendaría que el DAL devuelva una instancia de lo que sea mi Business Object en sí, ¿correcto? Estaba un poco confundido por su redacción de "objetos de datos", pero creo que lo entiendo. De esa manera, mi código podría solicitar un Business Object desde donde lo necesite (no a través de ellos mismos), simplemente llamando BusinessObject bo = DAL.LoadRecord(id);: ¿suena bien? La lógica para mapear la consulta al BO estaría contenida dentro del DAL, y solo allí.
1
@Scott Eso es correcto, aunque llamaría al método DAL algo así en Getlugar de Load, comoCustomer c = DAL.GetCustomer(id);
Rachel
2

Mi método, incluso antes de LINQ-To-SQL y Entity Framework, era tener una interfaz y una biblioteca de clase abstracta que proporcionara un "contrato escrito" para la comunicación entre las diferentes capas de la aplicación. Esto a veces se llama ontología , una definición para un dominio de trabajo. Todo lo que pasó entre capas usó este 'contrato'.

No me gusta la idea de pasar objetos de conjunto de datos sin procesar de la capa de datos a la capa empresarial. He visto este resultado en una serie de problemas, especialmente al integrar fuentes de datos heredadas. También puede hacer que sea muy difícil para las personas nuevas que entran en un proyecto comprender de dónde provienen los datos. Por último, requiere que su capa empresarial esté en el negocio de manejar datos directamente desde la base de datos, lo que puede ocasionar complicaciones en el futuro.

El código de ejemplo que tenía se parece al código que tenía antes de LINQ. Tenía una clase de función DB común que usaba dentro de mis objetos DAL. Las clases DAL leerían los datos y los encajarían en los objetos 'contract'. Los resultados escalares, como su ejemplo de eliminación, devolverían un valor, generalmente un valor booleano.

jfrankcarr
fuente
1
"No me gusta la idea de pasar objetos de conjunto de datos sin procesar de la capa de datos a la capa empresarial". Esta. Mil veces, esto.
Joshua Smith
@jfrankcarr: mi DAL realmente implementa una interfaz, y planeo tener interfaces para todo lo que transfiere datos de capa a capa, así que creo que nuestras ideas de patrones coinciden allí. Entonces, ¿me recomiendan cambiar los métodos que devuelven el resultado directo de las ExecuteScalarconsultas para devolver valores que tengan más sentido para una capa empresarial, como por ejemplo bool? Creo que de lo contrario, esta es una respuesta muy similar a la de Rachel.
Normalmente devuelvo un booleano para crear / actualizar / eliminar llamadas a menos que necesite la cantidad de registros afectados. Por ejemplo, podría devolver un int si un proceso almacenado está procesando varias líneas de pedido o algo así.
jfrankcarr
0

Su DAL debe devolver un conjunto de datos. Ese conjunto de datos devuelto debe ser el objeto comercial, no debe haber nada que deba hacer aparte de verificar que tenga los datos esperados. Si necesita hacer más con él, entonces está intentando hacer demasiado en un solo procedimiento almacenado o no está devolviendo los datos correctamente en el procedimiento almacenado.

Ryathal
fuente
0

Recomiendo que sus objetos de negocios tengan un constructor para rellenarse a sí mismos a partir de un conjunto de resultados. Esto elimina el acoplamiento entre su DAL y la capa empresarial. Si desea aislar completamente los dos, cree un mapa simple de pares de nombre de columna => valor de su conjunto de resultados y páselo al constructor.

TMN
fuente