Leí recientemente que no es una buena práctica usar el patrón de repositorio junto con un ORM. Según tengo entendido, esto se debe a que la abstracción que proporcionan sobre la base de datos SQL es demasiado permeable para que el patrón la contenga.
Tengo un par de preguntas sobre esto:
¿Qué haces si quieres cambiar los ORM? Tendría un código ORM específico en su aplicación si no lo contiene en un repositorio.
¿Sigue siendo válido el patrón de repositorio cuando no está usando un ORM y está usando ADO.NET para acceder a los datos y llenar los datos del objeto usted mismo?
Si usa un ORM pero no el patrón de repositorio, ¿dónde guarda las consultas de uso común? ¿Sería prudente representar cada consulta como una clase y tener algún tipo de fábrica de consultas para crear instancias?
fuente
Respuestas:
1) Verdadero, pero ¿con qué frecuencia cambia un ORM?
2) Yo diría que sí, porque un contexto ORM es una especie de repositorio y esconde mucho trabajo que implica crear consultas, recuperar datos, mapear, etc. Si no usa un ORM, esa lógica aún debe residir en algún lugar. Sin embargo, no sé si eso calificaría como el patrón de repositorio en el sentido más estricto de la palabra ...
3) Encapsular consultas es algo que veo con frecuencia, pero eso generalmente es más para fines de prueba / stubbing. Aparte de eso, sería cuidadoso al reutilizar una consulta en diferentes partes de una aplicación, porque entonces corre el riesgo de crear una dependencia en algo que podría cambiar n veces (n es el número de lugares donde utiliza la consulta).
fuente
Todavía no he estado en una posición donde la compañía, de repente, decidió cambiar la tecnología de acceso a datos. Si esto sucede, se requerirá algo de trabajo. Tiendo a abstraer las operaciones de acceso a datos a través de interfaces. El repositorio es una forma de resolver esto.
Entonces tendría un ensamblaje diferente para la implementación concreta de mi capa de acceso a datos. Por ejemplo, podría tener:
Company.Product.Data
yCompany.Product.Data.EntityFramework
asambleas. El primer ensamblado se usaría exclusivamente para interfaces, cuando otro sería una implementación concreta de la lógica de acceso a datos de Entity Framework.Creo que depende de usted decidir qué patrón es válido o no. He usado un patrón de repositorio en la capa de presentación. Una cosa a tener en cuenta es que a las personas les gusta poner responsabilidades en los repositorios. Antes de que te des cuenta, tu clase de repositorio será bailar, cantar y hacer todo tipo de cosas. Quieres evitar esto.
He visto una clase de repositorio que comenzó teniendo las responsabilidades GetAll, GetById, Update y Delete, lo cual está bien. Para cuando se completó el proyecto, esa misma clase tenía docenas de métodos (responsabilidades) que nunca deberían haber estado allí. Por ejemplo, GetByForename, GetBySurname, UpdateWithExclusions y todo tipo de cosas locas.
Aquí es donde entran en juego las consultas y los comandos.
Creo que es una muy buena idea tener consultas y comandos de uso en lugar de repositorios. Hago lo siguiente:
Definir interfaz para una consulta. Esto lo ayudará a realizar pruebas unitarias. P.ej
public interface IGetProductsByCategoryQuery { ... }
Definir implementación concreta para una consulta. Podrá inyectarlos a través del marco de IoC que elija. P.ej
public class GetProductsByCategoryQuery : IGetProductsByCategoryQuery
Ahora, en lugar de contaminar el repositorio con docenas de responsabilidades, simplemente agrupo mis consultas en espacios de nombres. Por ejemplo, una interfaz para la consulta anterior puede vivir:
Company.SolutionName.Products.Queries
y la implementación puede vivir enCompany.SolutionName.Products.Queries.Implementation
Cuando se trata de actualizar o eliminar datos, uso el patrón de comando de la misma manera.
Algunos podrían estar en desacuerdo y decir que antes de que se complete el proyecto, tendrá docenas de clases y espacios de nombres. Sí lo harás. En mi opinión, es bueno, ya que puede navegar a través de la solución en IDE de su elección y ver instantáneamente qué tipo de responsabilidades tiene cierto componente. Si ha decidido utilizar un patrón de repositorio en su lugar, tendrá que mirar dentro de cada clase de repositorio tratando de resolver sus responsabilidades.
fuente
DESCARGO DE RESPONSABILIDAD: Lo que sigue se basa en mi comprensión y breve experiencia de dicho patrón (Repositorio que es). Podría estar haciéndolo mal ... de hecho, estoy bastante seguro de que lo estoy haciendo mal :). Entonces, si bien este es un intento de respuesta, también es una pregunta disfrazada.
Estoy usando el patrón Repository para abstraer la capa de acceso a datos, que en la mayoría de los casos es un ORM. Es una interfaz genérica, con métodos para Crear, Leer, Actualizar, Eliminar e implementar clases para LINQ to SQL y EF hasta ahora. Podría hacer una implementación que escriba en archivos XML en el disco (solo un gran ejemplo de lo que podría hacer con él). No estoy implementando la Unidad de trabajo, ya que cuenta con el respaldo de los ORM. Si es necesario, probablemente podría implementarlo. Me gusta de esta manera porque, hasta ahora, me ha dado una buena separación. No digo que no haya mejores alternativas.
Para responder tu pregunta:
Para darle otro ejemplo, los muchachos de Umbraco han extraído el contenedor DI, en caso de que quieran cambiar a otra cosa.
fuente
Si el ORM ofrece flexibilidad de LINQ, carga ansiosa, etc., no lo escondería detrás de ninguna capa adicional.
Si se trata de sql sin formato (micro ORM), el "método por consulta" se debe utilizar de todos modos para lograr la reutilización, lo que hace que el patrón de repositorio sea un buen ajuste.
¿Por qué necesitarías cambiar?
Se debe usar el que tenga la mayoría de las características que necesita. Es posible que una nueva versión de ormX traiga nuevas funciones y resulte ser mejor que la actual, pero ...
Si elige ocultar la orm, solo puede usar las funciones que todos los candidatos tienen en común.
Por ejemplo, no puede usar
Dictionary<string, Entity>
propiedades en sus entidades porque ormY no puede manejarlas.Suponiendo que se utiliza LINQ, la mayoría de los conmutadores de orm solo cambian las referencias de la biblioteca y se reemplazan
session.Query<Foo>()
concontext.Foos
o similares hasta que se compilan. Tarea aburrida, pero lleva menos tiempo que codificar la capa de abstracción.Sí. El código debe ser reutilizable y eso significa colocar el edificio sql, la materialización de objetos, etc. en un solo lugar (clase separada). También puede llamar a la clase "XRepository" y extraer una interfaz de ella.
Suponiendo que se usa LINQ, un contenedor de clase sería excesivo en mi humilde opinión. Una mejor manera sería métodos de extensión
Cualquier código que se use en varios lugares (o que tenga el potencial) y sea lo suficientemente complicado (propenso a errores), debe extraerse a un lugar centralizado.
fuente