none
Patron repositorio y DAL RRS feed

  • Pregunta

  • Hola.

    He creado un patrón repositorio (y su respectivo Unit Of Work) utilizando MVC y Entity Framework, todo funciono bien pero ahora se me pidió implantar el patrón repositorio en una aplicación por capas para Windows Forms, sin utilizar Entity Framework, aquí mis preguntas son dos;

    1. Supongamos en mi patron tengo la interfaz IRepositorioex y RepositorioEx como la clase implementadora de la interfaz La conexión a mi base de datos en SQL Server se debe realizar desde la clase RepositorioEx ?

    2. las operaciones sobre la base de datos se deben crear en la clase RepositorioEx? es decir, no debo utilizar la capa DAL(Data Access Layer) sino que ahora la conexión y las operaciones sobre la base de datos las realizo en RepositorioEx? utilizar patrón repositorio significa no tener DAL?

    Para finalizar tendrán algún ejemplo donde se implemnete el patrón repositorio sin utilizar EF? no puedo encontrarlos en internet...Gracias por la ayuda.


    pabletoreto

    lunes, 12 de enero de 2015 14:19

Respuestas

  • >>la conexión y las operaciones sobre la base de datos las realizo en la clase RepositorioEx que implementa la interfaz IRepositorioEx?

    es lo que comente en el punto 1, depende

    puedes crearlo o puedes inyectar la instancia de la conexion, recuerda que ado.net implementa interfaces como se IDbConnection

    si quieres podrias desde el UoW o con IoC inyectar la instancia de la conexion y usar la misma por transaccion, esto aplciaria mas si usas el BeginTransaction

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    • Marcado como respuesta pabletoreto lunes, 12 de enero de 2015 16:23
    lunes, 12 de enero de 2015 16:14

Todas las respuestas

  • Tal como yo lo interpreto, el Repositorio es un "intermediario" entre la capa de negocio y la capa de acceso a datos. Es decir, el repositorio consiste simplemente en una serie de métodos tales como "LeerDatos", "GrabarDatos", "BuscarDatos" y similares, que serán llamados desde las capas "superiores" cada vez que requieran acceder a base de datos. Por dentro, esos métodos del repositorio estarán implementados mediante llamadas a la capa de acceso a datos que estés utilizando, tanto si dicha capa de acceso a datos está hecha con Entity Framework como si la has implementado con cualquier otra tecnología.

    Por lo tanto, usar un repositorio no significa no tener DAL. Lo que significa es que la DAL queda "oculta" desde el punto de vista de las capas superiores.

    Lo que ocurre en algunos casos es que si la DAL es "trivial" (es decir, no hemos programado en ella prácticamente nada, por ejemplo, cada método de la DAL consiste en una única línea de código que simplemente llama a Entity Framework), pues entonces no se escribe expresamente como una capa separada, sino que todo su código se mete directamente dentro de las propias funciones del repositorio. Pero eso no significa que no tengamos una funcionalidad equivalente a la DAL, simplemente lo que ocurre es que no la hemos separado explícitamente en una clase o conjunto de clases independientes.

    • Propuesto como respuesta Jesús López lunes, 12 de enero de 2015 18:13
    lunes, 12 de enero de 2015 15:09
    Moderador
  • Tal como yo lo interpreto, el Repositorio es un "intermediario" entre la capa de negocio y la capa de acceso a datos. Es decir, el repositorio consiste simplemente en una serie de métodos tales como "LeerDatos", "GrabarDatos", "BuscarDatos" y similares, que serán llamados desde las capas "superiores" cada vez que requieran acceder a base de datos. Por dentro, esos métodos del repositorio estarán implementados mediante llamadas a la capa de acceso a datos que estés utilizando, tanto si dicha capa de acceso a datos está hecha con Entity Framework como si la has implementado con cualquier otra tecnología.

    Por lo tanto, usar un repositorio no significa no tener DAL. Lo que significa es que la DAL queda "oculta" desde el punto de vista de las capas superiores.

    Lo que ocurre en algunos casos es que si la DAL es "trivial" (es decir, no hemos programado en ella prácticamente nada, por ejemplo, cada método de la DAL consiste en una única línea de código que simplemente llama a Entity Framework), pues entonces no se escribe expresamente como una capa separada, sino que todo su código se mete directamente dentro de las propias funciones del repositorio. Pero eso no significa que no tengamos una funcionalidad equivalente a la DAL, simplemente lo que ocurre es que no la hemos separado explícitamente en una clase o conjunto de clases independientes.

    Hola, gracias por la respuesta.

    significa que en un proyecto con el patrón repositorio debidamente implementado, la clase que implementa la interfaz hará una referencia a DAL? en tal caso no necesito Unit Of Work? digo porque mejor me hago una transacción en DAL que me abarque las operaciones sobre las distintas entidades de negocio.


    pabletoreto

    lunes, 12 de enero de 2015 15:19
  • El pequeño gran detalle con implementar un repositorio es implementar algo como IQueryable.  Yo siempre he trabajado sin ORM's y por lo complejo del asunto no me he atrevido a implementar un repositorio completo.  Tal vez debería sentarme a pensarlo en mi tiempo libre.  En fin, es lo que es.

    Al punto:  Como no he dado nunca a un repositorio la flexibilidad que da IQueryable, lo que he hecho es partirlo, ni modo:  Creo un repositorio con Unit Of Work para guardar cambios a entidades, pero no proveo la acción de recuperar entidades desde el repositorio.  En vez de eso suelo implementar servicios por tipo de entidad.  Cada interfase de servicio me provee métodos específicos para obtener las entidades según las necesidades del negocio y de la naturaleza de cada entidad.  Casi todas las entidades suelen tener un servicio con métodos para listar todos y para listar uno por clave primaria.  Lo que suele cambiar entre entidades es el o los métodos de búsqueda según distintos criterios y campos.

    Sé que no es lo ideal y que definitivamente no es un repositorio completo, pero funciona y me evita el dolor de cabeza de IQueryable.

    Para la parte que sí he hecho:  Suelo tener una capa definitoria de interfases y otros detalles.  Una de esas interases es ITransaction con métodos Begin(), Commit() y Rollback().  Es la base de Unit Of Work.  El repositorio tiene métodos Save() y Delete() que lo que hacen es listar las entidades en una lista interna que define la entidad y la acción a realizar (Save se traduce a INSERT o UPDATE dependiendo si la entidad es nueva o no, que suelo identificar porque los nuevos tienen ID = 0).  Ah, también un método PersistChanges() que hace el "playback" de las acciones guardadas en la lista interna en el contexto de una transacción.

    Esa es la parte fácil del repositorio.  La dura es la que no hago, jeje.

    La conexión a base de datos debe hacerse fuera del repositorio.  ¿Por qué?  Porque si no el repositorio sirve solamente para un tipo específico de base de datos.

    Las operaciones CRUD (que imagino es lo que pregunta en #2) se realizan también fuera del repositorio por la misma razón que el párrafo anterior.  En mi caso cuando lo he hecho es que cada entidad sabe el servicio de guardado (otra interfase en la capa de definición de interfases que yo llamo DAL).  Entonces cuando se llama a Save() o Delete(), el repositorio sabe cómo extraer esa info de la entidad y la almacena en la lista de ejecución como un delegate.  Tanto la función de guardado como de borrado en mi caso tienen la misma firma, así que el mismo tipo de delegado funciona para mí.  Esto me es posible gracias a que uso un Data Transfer Object genérico (basado en Dictionary<string, object>).

    En fin, eso es una pequeña pincelada de lo que se necesita, y sé que no es completo.  Sería muchísimo escribir explicar más que esto.

    Tal vez lo mejor es que se "eche al agua a nadar" y vaya preguntando según le aparezcan las dudas.


    Jose R. MCP
    Code Samples

    lunes, 12 de enero de 2015 15:25
    Moderador
  • >>1. Supongamos en mi patron tengo la interfaz IRepositorioex y RepositorioEx como la clase implementadora de la interfaz La conexión a mi base de datos en SQL Server se debe realizar desde la clase RepositorioEx ?

    que significa la "Ex" en los nombres que defines ?

    en realidad depende:

    - puedes hacer el el UoW sea quien inyecte la instancia de la conexion al repositorio

    - puedes hacer que algun framework de IoC la inyecte en el constructor del repositorio

    - podrias definirla en cada metodo del repositorio dentro de un bloque using

    imagino si tienes claro que UoW es quien administrara las transacciones, por eso el primer punto, si usas TransactionScope puedes darte algunas libertades, pero si usas el BeginTransaction del SqlConnection deberia pasar la instancia del mismo a los repositorior involucrados

    >>2. las operaciones sobre la base de datos se deben crear en la clase RepositorioEx? es decir, no debo utilizar la capa DAL(Data Access Layer) sino que ahora la conexión y las operaciones sobre la base de datos las realizo en RepositorioEx? utilizar patrón repositorio significa no tener DAL?

    es que el Repository seria tu DAL, para que crear dos capas de datos

    >>Para finalizar tendrán algún ejemplo donde se implemnete el patrón repositorio sin utilizar EF?

    quizas ayude

    Unit of work sample implementation for ADO.NET

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina


    lunes, 12 de enero de 2015 15:41
  • El pequeño gran detalle con implementar un repositorio es implementar algo como IQueryable.  Yo siempre he trabajado sin ORM's y por lo complejo del asunto no me he atrevido a implementar un repositorio completo.  Tal vez debería sentarme a pensarlo en mi tiempo libre.  En fin, es lo que es.

    Al punto:  Como no he dado nunca a un repositorio la flexibilidad que da IQueryable, lo que he hecho es partirlo, ni modo:  Creo un repositorio con Unit Of Work para guardar cambios a entidades, pero no proveo la acción de recuperar entidades desde el repositorio.  En vez de eso suelo implementar servicios por tipo de entidad.  Cada interfase de servicio me provee métodos específicos para obtener las entidades según las necesidades del negocio y de la naturaleza de cada entidad.  Casi todas las entidades suelen tener un servicio con métodos para listar todos y para listar uno por clave primaria.  Lo que suele cambiar entre entidades es el o los métodos de búsqueda según distintos criterios y campos.

    Sé que no es lo ideal y que definitivamente no es un repositorio completo, pero funciona y me evita el dolor de cabeza de IQueryable.

    Para la parte que sí he hecho:  Suelo tener una capa definitoria de interfases y otros detalles.  Una de esas interases es ITransaction con métodos Begin(), Commit() y Rollback().  Es la base de Unit Of Work.  El repositorio tiene métodos Save() y Delete() que lo que hacen es listar las entidades en una lista interna que define la entidad y la acción a realizar (Save se traduce a INSERT o UPDATE dependiendo si la entidad es nueva o no, que suelo identificar porque los nuevos tienen ID = 0).  Ah, también un método PersistChanges() que hace el "playback" de las acciones guardadas en la lista interna en el contexto de una transacción.

    Esa es la parte fácil del repositorio.  La dura es la que no hago, jeje.

    La conexión a base de datos debe hacerse fuera del repositorio.  ¿Por qué?  Porque si no el repositorio sirve solamente para un tipo específico de base de datos.

    Las operaciones CRUD (que imagino es lo que pregunta en #2) se realizan también fuera del repositorio por la misma razón que el párrafo anterior.  En mi caso cuando lo he hecho es que cada entidad sabe el servicio de guardado (otra interfase en la capa de definición de interfases que yo llamo DAL).  Entonces cuando se llama a Save() o Delete(), el repositorio sabe cómo extraer esa info de la entidad y la almacena en la lista de ejecución como un delegate.  Tanto la función de guardado como de borrado en mi caso tienen la misma firma, así que el mismo tipo de delegado funciona para mí.  Esto me es posible gracias a que uso un Data Transfer Object genérico (basado en Dictionary<string, object>).

    En fin, eso es una pequeña pincelada de lo que se necesita, y sé que no es completo.  Sería muchísimo escribir explicar más que esto.

    Tal vez lo mejor es que se "eche al agua a nadar" y vaya preguntando según le aparezcan las dudas.


    Jose R. MCP
    Code Samples

    Gracias.

    Lo que pasa es que yo he utilizado Repository Pattern con EF y ahi con el DBContext y DbSet mantienes la persistencia sobre tu modelo por eso no necesite una capa extra para manejar mis datos pues como mencionaba Albeto Poblacion, resulto ser un caso trivial...

    Si no voy a hacer ninguna operación en mi Repository Pattern entonces creo(muy mi opinion) que se esta trabajando de mas, te pido tu opinión: mejor me hago una interfaz que llamo desde mi DAL y de paso la aprovecho para Independendy Injection y en esa interfaz declaro los metodos correspondientes a las operaciones sobre la base de datos asi no hago uso del Repository Pattern.

    Me llamo la atención lo de tu interfaz ITransaction con los metodos Begin(), Commit() y Rollback() pero porque declaras esos metodos? me imagino los utiizas para mantener la persistencia sobre una BD pero al declarar una transaccion el begin, commit y rollback van implicitos o estoy mal? te pregunto mas para aprender que para cuestionar tu forma de codificar.


    pabletoreto

    lunes, 12 de enero de 2015 15:43
  • >>Si no voy a hacer ninguna operación en mi Repository Pattern entonces creo(muy mi opinion) que se esta trabajando de mas, te pido tu opinión: mejor me hago una interfaz que llamo desde mi DAL y de paso la aprovecho para Independendy Injection

    es que es lo mismo, llamalo DAL o Repisitory es el mismo concepto, siempre vas a crear una interfaz que provea los metodos de acceso a los datos

    lo que tu planteas es si vas a crear una funcionalidad generica para las operaciones contra la DB o no, y eso es otro tema diferente

    puedes crear una interfaz base y depsues a medida que avanzas con el desarrollo identificar funcionalidad comun y crear un nivel mas generico, no tienes porque definir todo desde el principio

    >>Me llamo la atención lo de tu interfaz ITransaction con los metodos Begin(), Commit() y Rollback() pero porque declaras esos metodos?

    eso se declara en el UoW para poder definir transacciones cuando realizas varias operaciones y debes realizar un roolback ante un fallo

    >>en tal caso no necesito Unit Of Work? digo porque mejor me hago una transacción en DAL que me abarque las operaciones sobre las distintas entidades de negocio.

    estas mezclando terminos que en definitiva son los mismo

    en tus planteos llevas al DAL a nivel del Repository y del UoW segun te convence y no es asi

    si implementas Repisitory y UoW olvidate del concepto de DAL porque es solo un nombre que se le da a una capa

    Repisitory y UoW juntos forman tu DAL

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    lunes, 12 de enero de 2015 15:57
  • >>1. Supongamos en mi patron tengo la interfaz IRepositorioex y RepositorioEx como la clase implementadora de la interfaz La conexión a mi base de datos en SQL Server se debe realizar desde la clase RepositorioEx ?

    que significa la "Ex" en los nombres que defines ?

    en realidad depende:

    - puedes hacer el el UoW sea quien inyecte la instancia de la conexion al repositorio

    - puedes hacer que algun framework de IoC la inyecte en el constructor del repositorio

    - podrias definirla en cada metodo del repositorio dentro de un bloque using

    imagino si tienes claro que UoW es quien administrara las transacciones, por eso el primer punto, si usas TransactionScope puedes darte algunas libertades, pero si usas el BeginTransaction del SqlConnection deberia pasar la instancia del mismo a los repositorior involucrados

    >>2. las operaciones sobre la base de datos se deben crear en la clase RepositorioEx? es decir, no debo utilizar la capa DAL(Data Access Layer) sino que ahora la conexión y las operaciones sobre la base de datos las realizo en RepositorioEx? utilizar patrón repositorio significa no tener DAL?

    es que el Repository seria tu DAL, para que crear dos capas de datos

    >>Para finalizar tendrán algún ejemplo donde se implemnete el patrón repositorio sin utilizar EF?

    quizas ayude

    Unit of work sample implementation for ADO.NET

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina


    Hola.

    La Ex = Example.

    Utilizo TransactionScope, aunque es mas general me parece..."me parece" que obtengo el mismo resultado que con el cmd.BeginTransaction con menos código.

    La respuesta 2 es justo lo que buscaba, no veo la necesidad de definir el repository Pattern y ademas la capa de datos, pero entonces Leandro, la conexión y las operaciones sobre la base de datos las realizo en la clase RepositorioEx que implementa la interfaz IRepositorioEx?


    pabletoreto

    lunes, 12 de enero de 2015 15:58
  • Hmm, pues no me parece que pueda hacerse totalmente implícito, ¿o sí?  El Begin() podría llamarse desde el constructor de la clase que implementa ITransaction, pero ¿cuándo hacer el Commit() y cuando el Rollback()?  Mi ITransaction hereda de IDisposable, así que IDisposable.Dispose() es un punto posible de automatización, pero ¿cuál acción?  Porque Dispose() correrá tanto cuando el código ejecuta limpiamente como cuando hay una excepción.  ¿Corro entonces Commit() o Rollback()?

    Yo la uso así:

    using (ITransaction tran = <objeto base de datos>.CreateTransaction()) //Aquí podría venir implícito el Begin().
    {
        try
        {
            //Aquí hago el playback de las acciones a realizar según lo expliqué.
            //Si llegamos aquí no ha habido problemas.
            tran.Commit();
        }
        catch(System.Exception ex)
        {
            //Hacer lo que deba hacerse con la excepción.
            //Luego hacer el rollback.
            tran.Rollback();
            //Luego arrojar alguna excepción, idealmente agnóstica al tipo de base de datos.
            throw <algo>;
        }
    }

    Si quisiera tener eso implícito, ¿cómo lo haría?  Soy todo oídos porque no soy ningún experto en el asunto.  Tengo la experiencia de algunos proyectos pero para nada me autodenominaría "experto".  Si tiene alguna idea de cómo manejar el asunto, genial. :-)


    Jose R. MCP
    Code Samples


    lunes, 12 de enero de 2015 16:04
    Moderador
  • >>la conexión y las operaciones sobre la base de datos las realizo en la clase RepositorioEx que implementa la interfaz IRepositorioEx?

    es lo que comente en el punto 1, depende

    puedes crearlo o puedes inyectar la instancia de la conexion, recuerda que ado.net implementa interfaces como se IDbConnection

    si quieres podrias desde el UoW o con IoC inyectar la instancia de la conexion y usar la misma por transaccion, esto aplciaria mas si usas el BeginTransaction

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    • Marcado como respuesta pabletoreto lunes, 12 de enero de 2015 16:23
    lunes, 12 de enero de 2015 16:14
  • EntityLite te proporciona repositorios para todas las entidades con métodos para insertar, actualizar, eliminar y consultar entidades. No hay necesidad de implementar el patrón de repositorio con EntityLite, ya te viene implementado.

    Entity Framework proporciona el interfaz IQueryable en sus entidades. Lo cual es la esencia pura del repositorio según lo define Martin Fowler:

    Repository

    Y yo me pregunto ¿Por qué hay tanta gente que, a pesar de todo, quiere implementar repositorios "a su manera"?

    No le veo ningún sentido.



    Jesús López


    EntityLite a lightweight, database first, micro orm

    lunes, 12 de enero de 2015 17:10