net - Entity Framework como Repository y UnitOfWork?
domain driven design c# example (3)
Estoy comenzando un nuevo proyecto y he decidido tratar de incorporar los patrones DDD y también incluir Linq en Entidades. Cuando miro el ObjectContext de EF, parece que está realizando las funciones de los patrones Repositorio y Unidad de trabajo:
Repositorio en el sentido de que la interfaz de nivel de datos subyacente se abstrae de la representación de la entidad y puedo solicitar y guardar datos a través del ObjectContext.
Unidad de trabajo en el sentido de que puedo escribir todas mis inserciones / actualizaciones en el objectContext y ejecutarlas todas de una vez cuando hago un SaveChanges ().
Parece redundante poner otra capa de estos patrones encima del EF ObjectContext? También parece que las clases de modelo se pueden incorporar directamente en la parte superior de las entidades generadas por EF usando ''clase parcial''.
Soy nuevo en DDD, por favor avíseme si me falta algo aquí.
Diría que debería mirar el ObjectContext como su UnitOfWork, y no como un repositorio.
Un ObjectContext no puede ser un repositorio -imho- ya que es ''genérico''. Debe crear sus propios repositorios, que tienen métodos especializados (como GetCustomersWithGoldStatus, por ejemplo) junto a los métodos regulares de CRUD.
Entonces, lo que haría sería crear repositorios (uno para cada raíz de agregado) y dejar que esos repositorios usen ObjectContext.
No creo que el Entity Framework sea una buena implementación de Repository, porque:
- El contexto del objeto no es lo suficientemente abstracto como para hacer una buena prueba unitaria de las cosas que hacen referencia a él, ya que está vinculado al acceso DB. En cambio, tener una referencia de IRepository funciona mucho mejor para crear pruebas unitarias.
- Cuando un cliente tiene acceso a ObjectContext, el cliente puede hacer casi cualquier cosa que le interese. El único control real que tiene sobre esto es hacer que ciertos tipos o propiedades sean privados. Es difícil implementar una buena seguridad de datos de esta manera.
- En un modelo no trivial, ObjectContext es insuficientemente abstracto. Puede, por ejemplo, tener asignadas tablas y procedimientos almacenados al mismo tipo de entidad. Realmente no desea que el cliente tenga que distinguir entre las dos asignaciones.
- En una nota relacionada, es difícil escribir normas comerciales y códigos de entidad completos y que se apliquen correctamente. De hecho, si esto es incluso una buena idea es discutible.
Por otro lado , una vez que tienes un ObjectContext, implementar el patrón Repository es trivial. De hecho, para los casos que no son particularmente complejos, el Repositorio es una especie de envoltorio alrededor de los tipos ObjectContext y Entity.
Me gusta tener una capa de repositorio por las siguientes razones:
EF gotcha''s
Cuando mira algunos de los tutoriales actuales sobre EF (versión de Code First), es evidente que hay que manejar una cantidad de gotcha, particularmente en torno a gráficos de objetos (entidades que contienen entidades) y escenarios desconectados. Creo que una capa de repositorio es ideal para envolverlos en un solo lugar.
Una imagen clara de los mecanismos de acceso a datos
Un repositorio proporciona una imagen específica de cómo el BL está accediendo y actualizando el almacén de datos. Expone métodos que tienen un único propósito claro y pueden probarse independientemente del BL. Ejemplo estándar de los libros de texto, Find () para encontrar una sola entidad. Un ejemplo más específico de la aplicación, Borrar () para borrar una tabla db.
Un lugar para optimizaciones
Inevitablemente te encuentras con golpes de rendimiento cuando utilizas EF vainilla. Uso el repositorio para ocultar los mecanismos de optimización del BL.
Ejemplos,
GetKeys () para proyectar claves en caché de las tablas (para decisiones de inserción / actualización). La lectura de la clave solo es más rápida y utiliza menos memoria que la lectura de la entidad completa.
Carga masiva a través de SqlBulkCopy. EF lo insertará mediante declaraciones SQL individuales. Si desea que una sola instrucción inserte varias filas, SqlBulkCopy es un buen mecanismo. El repositorio encapsula esto y proporciona metadatos para SqlBulkCopy. Además del método Insert, necesita un método StartBatch () y EndBatch (), que también es un argumento para una capa UnitOfWork.