c# - tutorial - Confusión acerca de dónde poner la lógica empresarial al usar el marco de la Entidad
entity framework database first (5)
El marco de la entidad, a diferencia de linq-to-sql, por ejemplo, se diseñó teniendo en cuenta la separación entre el modelo de datos y el modelo conceptual. Admite inheritance , división de entidades , división de tablas , tipos complejos y asociaciones transparentes de muchos a muchos , todos los cuales permiten moldear el modelo de dominio según las necesidades sin estar demasiado restringido por el modelo del almacén de datos.
El enfoque de primer código permite trabajar con POCO en el que las propiedades seleccionadas se pueden asignar a las columnas del almacén de datos. Primera generación de primer modelo y primera base de datos generan clases parciales, lo que permite extender el código generado. Trabajar con esas clases tiene la apariencia de trabajar con POCO. Incluso más desde la versión 5, cuando DbContext
convirtió en la API predeterminada, por lo que las clases generadas ya no estaban rellenas con el código relacionado con la persistencia de la API ObjectContext
.
Por supuesto, esta separación del modelo conceptual y el modelo de tienda solo puede tener éxito en cierta medida. Algunas cosas funcionan en contra de este objetivo de persistencia ignorancia . Por ejemplo, si la carga diferida es deseable, es necesario declarar las propiedades de navegación como virtual
, por lo que EF puede anularlas en los tipos de proxy. Y es muy conveniente tener propiedades de clave externa primitiva (por ejemplo, ParentId
) que acompañan a las asociaciones "reales" (una referencia de Parent
). Los puristas consideran que esto es una violación del diseño impulsado por el dominio.
Otra violación importante de la ignorancia de la persistencia es la gran cantidad de diferencias entre linq-to-objects y linq-to-entities . Simplemente no puede ignorar el hecho de que está conectando con un universo totalmente diferente a los objetos en la memoria. Esto se conoce como acoplamiento cerrado o abstracción con fugas .
Pero luego ... en general estoy contento con el uso de clases de EF generadas o POCO de un modelo de primer código como clases de dominio. Hasta ahora, nunca he visto una transición sin fricciones de un almacén de datos a otro, si es que sucede. La ignorancia de la persistencia es una ficción. Peculiaridades de DAL siempre dejan una huella en el dominio. Solo cuando tiene que codificar diferentes tiendas / modelos de datos o cuando se espera que las tiendas / modelos cambien con relativa frecuencia, vale la pena minimizar esta huella tanto como sea posible o abstraerla por completo.
Otro factor que puede promover las clases de EF como clases de dominio es que muchas aplicaciones hoy en día tienen múltiples niveles, donde los modelos de vistas diferentes (serializados) o los DTO se envían a un cliente. El uso de clases de dominio en interfaces de usuario casi nunca se ajusta a la ley. También puede usar las clases de EF como dominio y hacer que los servicios eliminen los modelos dedicados y los DTO según lo requiera un UI o los consumidores del servicio. Otra capa de abstracción puede ser más una carga que una bendición, solo en términos de rendimiento.
Acabo de empezar a trabajar con el marco Entity y estoy confundido acerca de cómo las clases normalmente en la capa empresarial se ajustan a las entidades creadas por Entity Framework.
Cuando trabaje con ADO.NET clásico, tendría una clase llamada Cliente por ejemplo y luego otra clase llamada DALCustomer para manejar la interacción con la base de datos, en esta estructura habría puesto el código para hacer cálculos, filtrado y cuidado una instancia de la conexión DAL Cliente para guardar, actualizar y eliminar en la clase Cliente.
Con Entity Framework, si tiene una tabla llamada Customer, el marco Entity crea una entidad llamada Customer y aquí es donde comienza mi confusión, ¿esta entidad elimina la necesidad de un Cliente en la capa de negocios? Entonces, ¿en esencia, todos los campos y métodos que normalmente van en la capa de negocios van en la entidad generada por Entity Framework? ¿O debería existir aún una clase en la capa empresarial llamada CustomerBL, por ejemplo, que aún contenga los campos y métodos necesarios para lograr la lógica de negocios necesaria para los cálculos y el filtrado, y aún necesita una instancia de EF DAL declarada para gestionar el acceso a los datos?
Si debe haber una clase de negocios, en este caso CustomerBL, otra pregunta surge de la mente, si los campos que se crean en la entidad del cliente se vuelven a crear en CustomerBL o si se debe declarar una instancia de la entidad del Cliente en CustomerBL para que haya no es necesario tener los campos declarados en 2 ubicaciones?
En mi opinión, el objetivo de utilizar POCO como entidades que pueden persistir es eliminar la distinción entre "entidades de base de datos" y "entidades comerciales". Se supone que las "entidades" son "entidades comerciales" que directamente pueden persistir y cargarse desde un almacén de datos y, por lo tanto, actúan como "entidades de base de datos" al mismo tiempo. Mediante el uso de POCO, las entidades comerciales están desacopladas del mecanismo específico para interactuar con una base de datos.
Puede mover las entidades a un proyecto separado, por ejemplo, que no tenga referencias a ningún ensamblaje de EF y, sin embargo, las use en un proyecto de capa de base de datos para administrar la persistencia.
Esto no significa que pueda diseñar completamente las entidades comerciales sin tener en cuenta los requisitos de EF. Existen limitaciones que debe conocer para evitar problemas cuando llegue al punto de asignar las entidades comerciales a un esquema de base de datos utilizando EF, por ejemplo:
- Debe hacer que las propiedades de navegación (referencias o colecciones de referencias a otras entidades) sean
virtual
para admitir la carga diferida con EF - No puede usar
IEnumerable<T>
para colecciones que deben persistir. Debe serICollection<T>
o un tipo más derivado. - No es fácil persistir propiedades
private
- El tipo
char
no es soportado por EF y no puedes usarlo si quieres persistir en sus valores - y más...
Pero un grupo adicional de entidades es, en mi opinión, una capa adicional de complejidad que debería justificarse para ser realmente necesaria si las limitaciones mencionadas son demasiado estrictas para su proyecto.
YA2C (Sin embargo, otros 2 centavos :)
Este tema quizás sea un poco antiguo, pero esto puede ayudar. Andras Nemes señaló en su blog la preocupación de utilizar DDD (diseño impulsado por dominio) sobre el diseño impulsado por la tecnología como EF, MVC, etc.
No sé si otros lo consideran una buena práctica, pero personalmente así es como manejé esto en el pasado:
Las clases generadas por EF son su DAL, y luego para BL crean un conjunto complementario de clases en el que tendrá la estructura que necesita (como quizás fusionar datos de entidades relacionadas en una relación de uno a uno) y se manejan otras preocupaciones de lógica de negocios (validación personalizada como implementar IDataErrorInfo para que funcione bien con la UI en WPF, por ejemplo) y también crear clases que contengan todos los métodos de la capa empresarial relacionados con un tipo de entidad, que usen instancias BL y conviertan hacia y desde entidades EF a los objetos BL.
Entonces, por ejemplo, tiene Cliente en su db. EF generará un cliente de clase, y en el BL habrá una clase de cliente (prefijo, sufijo, etc.) y una clase de CustomerLogic. En la clase Cliente BL puede hacer lo que sea necesario para satisfacer los requisitos sin tener que manipular las entidades EF y en la clase CustomerLogic tendrá métodos BL (cargar clientes más valorados, guardar datos adicionales del cliente, etc.).
Ahora, esto le permite estar ligeramente acoplado a la implementación del origen de datos. Otro ejemplo de por qué esto me ha beneficiado en el pasado (en un proyecto de WPF) es que puede hacer cosas como implementar IDataErrorInfo e implementar la lógica de validación en las clases de CustomerBL para que cuando enlace la entidad a un formulario de creación / edición en la UI se beneficiará de la funcionalidad integrada proporcionada por WPF.
... Mis 2 centavos, también tengo curiosidad por saber cuál es la mejor práctica o cuáles son otras soluciones / puntos de vista.
También, tal vez, relacionado con este tema: primer código frente a modelo / base de datos primero
Usé la lógica de negocios para escribir mis métodos y devolver los resultados en su vista creada como:
namespace Template.BusinessLogic
{
public interface IApplicantBusiness
{
List<Template.Model.ApplicantView> GetAllApplicants();
void InsertApplicant(Template.Model.ApplicantView applicant);
}
}