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á selects
en 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 DataSet
desde 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?
Respuestas:
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.fuente
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í.Get
lugar deLoad
, comoCustomer c = DAL.GetCustomer(id);
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.
fuente
ExecuteScalar
consultas para devolver valores que tengan más sentido para una capa empresarial, como por ejemplobool
? Creo que de lo contrario, esta es una respuesta muy similar a la de Rachel.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.
fuente
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.
fuente