sábado, 7 de noviembre de 2015

Mi implementación de Repository y Unit of Work


1. Repository


He definido una interfaz genérica que implementarán todos los repositories y además alguno de ellos implementará la suya propia (y cumplir con la I de SOLID )

La interfaz genérica es esta:

 public interface IRepository<T> : IDisposable where T : class
    {
        IQueryable<T> GetQueryable();
        IEnumerable<T> GetAll();
        IEnumerable<T> Find(Expression<Func<T, Boolean>> where);
        T Single(Expression<Func<T, Boolean>> where);
        T First(Expression<Func<T, Boolean>> where);
        void Delete(T entity);
        void Add(T entity);
        void Attach(T entity);
        void Attach(T entity, EntityStatus status);     

    }

Como vemos tiene definidos unos métodos genéricos para cualquier Repository. Podremos buscar todos los elementos, buscar uno en concreto o realizar búsquedas más complejas (método Find)

Recordar, que un Repository es una colección de objetos en memoria, por lo que los métodos Delete ó Add son para acciones sobre objetos en memoria; hasta que no usemos UoW para realizar la persistencia, no tendrán efecto los cambios en nuestra base de datos.

Bien, pero resulta que para los movimientos tendremos métodos específicos; por ejemplo, para conseguir un listado de movimientos paginados utilizaremos un procedimiento almacenado, igual que a la hora de recalcular el saldo de un usuario.
Podría haber optado por utilizar extension methods, pero me ha parecido más sencillo hacer una interfaz para Movimientos; queda algo así

  public interface IMovimientosRepository : IRepository<Movimientos>
    {
        /// <summary>
        /// Actualiza en base de datos el saldo de usuario.
        /// </summary>
        /// <param name="UserName">Nombre de usuario para actualizar saldo de movimientos</param>
        void UpdateSaldo(string UserName);
       /// <summary>
        /// Devuelve los movimientos de un usuario, realizando la paginacion indicada
       /// </summary>
       /// <param name="UserName">Usuario del que buscar movimientos</param>
       /// <param name="PageIndex">Numero de pagina a devolver</param>
       /// <param name="PageSize">Numero de movimientos por pagina</param>
       /// <returns></returns>
        IEnumerable<vwMovimientos> GetMovimientos(string UserName, string Filtro, int PageIndex, int PageSize = 10);
    }
Vemos que la interfaz implementa IRepository con lo que tendremos los métodos básicos de buscar y modificar, además de los propios para los movimientos.
  • Implementación de Repository
 public class Repository<T> :IRepository<T> where T : class
    {
        protected readonly IObjectContextAdapter _ObjectContextAdapter;
        public ObjectSet<T> _ObjectSet;

        public Repository(IObjectContextAdapter context)
        {
            _ObjectContextAdapter = context;
            _ObjectSet = context.ObjectContext.CreateObjectSet<T>();
        }

        public IQueryable<T> GetQueryable()
        {
            return _ObjectSet;
        }

        public IEnumerable<T> GetAll()
        {
            return _ObjectSet.ToList();
        }

        public IEnumerable<T> Find(Expression<Func<T, Boolean>> where)
        {
            return _ObjectSet.Where(where);
        }

        public T Single(Expression<Func<T, Boolean>> where)
        {
            return _ObjectSet.Single(where);
        }

        public T First(Expression<Func<T, Boolean>> where)
        {
            return _ObjectSet.First(where);
        }

        public void Delete(T entity)
        {
            _ObjectSet.DeleteObject(entity);
        }

        public void Add(T entity)
        {
            _ObjectSet.AddObject(entity);
        }

        public void Attach(T entity)
        {
            Attach(entity, EntityStatus.Unchanged);
        }

        public void Attach(T entity, EntityStatus status)
        {
            _ObjectSet.Attach(entity);
            _ObjectContextAdapter.ObjectContext.ObjectStateManager.ChangeObjectState(entity, GetEntityState(status));
        }
        
        public void Dispose()
        {
            if (_ObjectContextAdapter != null)
                _ObjectContextAdapter.ObjectContext.Dispose();

            GC.SuppressFinalize(this);
        }

        private EntityState GetEntityState(EntityStatus status)
        {
            switch (status)
            {
                case EntityStatus.Added:
                    return EntityState.Added;
                case EntityStatus.Deleted:
                    return EntityState.Deleted;
                case EntityStatus.Detached:
                    return EntityState.Detached;
                case EntityStatus.Modified:
                    return EntityState.Modified;
                default:
                    return EntityState.Unchanged;
            }
        }
    }
  • Implementación de Movimientos Repository
 public class MovimientosRepository : Repository<Movimientos>, IMovimientosRepository

    {
        public MovimientosRepository(IObjectContextAdapter context)
            : base(context)
        {

        }
        public void UpdateSaldo(string UserName)
        {
            SqlParameter parameter = new SqlParameter("@UserName", SqlDbType.NVarChar);
            parameter.Value = UserName;
            _ObjectContextAdapter.ObjectContext.ExecuteStoreCommand("Exec RecalculaSaldo @UserName", parameter);
        }

        public IEnumerable<vwMovimientos> GetMovimientos(string UserName, string Filtro, int PageIndex, int PageSize = 10)
        {
            var userNameParameter = new SqlParameter("@UserName", UserName);
            var PageIndexParameter = new SqlParameter("@PageIndex", PageIndex);
            var PageSizeParameter = new SqlParameter("@PageSize", PageSize);
            var filtroParameter = new SqlParameter("@Filtro", Filtro);
            var result = _ObjectContextAdapter.ObjectContext.ExecuteStoreQuery<vwMovimientos>("exec GetMovimientos @UserName, @PageIndex, @PageSize, @Filtro", userNameParameter, PageIndexParameter, PageSizeParameter, filtroParameter).ToList();

            return result;
        }
    }

Vemos que MovimientosRepository hereda de Repository e implementa IMovimientosRepository.
Queda claro que, como veiamos en la entrada anterior, con el uso de Repository estamos evitando repetir el código que obtiene los movimientos de un usuario.
Además, todavía no hemos hablado de EF por ninguna parte ;-)

2. Unit of Work

Y ahora Unit of Work. Su interfaz

 public interface IUnitOfWork : IDisposable
    {
        IRepository<T> Repository<T>() where T : class;
        IMovimientosRepository MovimientosRepo { get; }
        void SaveChanges();
    }
Bien sencilla; sólo tener en cuenta que debe implementar IDisposable y que debe tener un método para realizar la persistencia (SaveChanges en este caso)
Tendremos una lista de Repository genéricos y acceso al Repository de Movimientos.

Y aquí la implementación:

public class UnitOfWork : IUnitOfWork
    {
        private readonly IObjectContextAdapter _ObjectContextAdapter;        
        public Dictionary<Type, object> repositories = new Dictionary<Type, object>();
        
        public UnitOfWork(IObjectContextAdapter objectContextAdapter)
        {
            _ObjectContextAdapter = objectContextAdapter;
            MovimientosRepo = new MovimientosRepository(_ObjectContextAdapter);
        }
       
        public IRepository<T> Repository<T>() where T : class
        {
            if (repositories.Keys.Contains(typeof(T)) == true)
            {
                return repositories[typeof(T)] as IRepository<T>;
            }
            IRepository<T> repo = new Repository<T>(_ObjectContextAdapter);
            repositories.Add(typeof(T), repo);
            return repo;
        }
        public IMovimientosRepository MovimientosRepo { get; private set; }
        public void SaveChanges()
        {
            try
            {
                _ObjectContextAdapter.ObjectContext.SaveChanges();
            }
            catch (OptimisticConcurrencyException oce)
            {
                //TODO:Elevar la excepcion                
                //throw new ConcurrencyException(oce.Message, oce.InnerException);
            }
            catch (DataException)
            {
                throw;
            }
        }
       

        public void Dispose()
        {
            if (_ObjectContextAdapter != null)
                _ObjectContextAdapter.ObjectContext.Dispose();

            GC.SuppressFinalize(this);
        }
    }
Si nos fijamos en el constructor de las clase UnitOfWork, vemos que recibe como parámetro la interfaz IObjectContextAdapter; no recibe ningún contexto concreto, solo una interfaz; seguimos trabajando con abstracciones y no con implementaciones concretas.


Bien, pues en la siguiente entrada, veremos cómo usamos todo esto desde nuestra capa de Services

jueves, 5 de noviembre de 2015

Consideraciones previas sobre Repositoy y Unit of Work

Antes de ver cómo he realizado la implementación de Repository y Unit of Work, me gustaría comentar alguna cosa.


  1. Repository

Definición
Es el intermediario entre la capa de dominio y el framework de persistencia; es una colección de objetos del dominio en memoria sobre los que podemos hacer acciones CRUD (siempre en memoria) o consultas


¿Qué nos aporta utilizar Repositories?
Bajo mi modesta opinión, tenemos tres ventajas:

  • Reducción de duplicidad de consultas.
  • Nos desacopla de los frameworks de persistencia
  • Nos facilita los test


  1. Unit of Work
Definición
Se encarga de realizar la persistencia de los objetos modificados en memoria.


Hay gente que considera que no es necesario reimplementar este patrón utilizando Entity Framework porque éste ya lo es. Es cierto que lo implementa, pero por si solo, creo que tiene algunos puntos que no me convencen

Con EF tenemos DbSet que actuan como Repository; en DbSet tenemos los mismos métodos que tenemos en un Repository (Add, Remove, ....)
También es cierto que tenemos DbContext que implementa Unit of Work y que coordina las actualizaciones de los objetos modificados en memoria (DbSet)
Pero con dbSet:

  • No evitamos repetir consultas; si queremos saber los movimientos de un usuario entre un rango de fechas, tenemos que repetir la consulta tantas veces como la necesitemos.... a no ser que lo encapsulemos en una clase (Repository?) o implementemos cualquier otra solución
  • No nos desacoplamos del framework de persistencia. Bueno, esta parece clara.

y con DbContext, la dependencia con EF es evidente.

Por eso creo que EF por si solo no implementa este patrón y por eso he decidido hacer mi implementación que veremos en la próxima entrada.


lunes, 5 de octubre de 2015

Capa DAL - Entity Framework.

Como comentaba en la entrada previa, vamos a ver el primer proyecto que compone nuestra solución.
Es la capa DAL (Data Access Layer) que nos va a ayudar con la persistencia de datos.

Para ello usamos Entity Framework, que de manera resumida, es un conjunto de tecnologías ADO .NET que genera un modelo de datos ligado directamente con la base de datos. Es decir, que con EF manejamos objetos y nos abstraemos de las sentencias SQL para leer o actualizar la base de datos.
Por ejemplo, en el proyecto que nos ocupa, tenemos una tabla Conceptos para indicar el concepto de un movimiento (si es un gasto de Gasoil, un ingreso por nómina, ....)
Bien pues con EF, tendremos un objeto Concepto, con los mismos atributos (propiedades) que la tabla subyacente en SQL Server (columnas), pero cuando queramos modificar un concepto haremos algo como esto (no es código literal)

  concepto.Descripcion = "Descripcion 1"
  contexto.Save();

Y EF se encargará de generar la sentencia UPDATE correspondiente.

Alguna vez me han comentado que en algunas circunstancias, EF no tiene un buen rendimiento. Mi experiencia, con varias aplicaciones de uso intensivo de base de datos, es bastante buena. Nunca he tenido problemas de rendimiento causados por EF; siempre han sido vistas o procedimientos mal diseñados/programados. Ahora bien, es cierto que cumplo una norma. Quien mejor maneja los datos, es la base de datos y nunca hago joins que tenga que gestionar EF.
Si observamos el modelo de datos que publiqué, vemos que hay una vista (vwMovimientos) que se encarga de unir las tablas que necesito para mostrar la información de movimientos. (Pongo el código para verlo más fácilmente)

Alter View vwMovimientos as 
Select Movimientos.Id, UserName, FechaMovimiento, IdConcepto, Importe,Saldo, Conceptos.Descripcion as Concepto
From Movimientos
Inner Join Conceptos ON Conceptos.Id = Movimientos.IdConcepto
order by FechaMovimiento Desc

Bueno, se ve que es un join sencillo; pero me preocupa perder el control. Si mañana necesito depurar esta vista, desde SQL Server lo puedo hacer; si tengo que crear un índice, desde SQL Server lo puedo hacer. Evidentemente lo mismo puedo hacer para que funcione correctamente desde EF, pero tengo la sensación de perder un poco el control.
Un objeto de mi modelo puede estar mapeado, a la hora de la lectura, con varios objetos de EF.



Creando el modelo en EF

Para crear los objetos de EF, nos posicionamos sobre nuestro proyecto (en este caso EliteDAL) y con el botón derecho del ratón, seleccionamos añadir nuevo elemento. En el menú izquierdo, seleccionamos Data y en el centro pulsamos sobre ADO .NET Entity Data Model y ponemos un nombre a nuestro modelo


Después seleccionamos Code First from database, para generar nuestro conjunto de tipos POCO.



Seleccionamos una conexión y finalmente escogemos las entidades de la base de datos que vamos a pasar a nuestro modelo de EF

Al darle finalizar, veremos que automáticamente tenemos nuestros objetos POCO, listos para ser usados.


En la próxima entrada seguiremos con nuestro proyecto DAL, añadiendo Unit of Work.

martes, 22 de septiembre de 2015

Contenedores de Inversión de Control (IoC Containers)

Como vimos en la entrada anterior, hemos conseguido evitar el acoplamiento entre distintas clases de nuestra aplicación utilizando la inyección de dependencias. En nuestro caso, utilizamos inyección por constructor, es decir, en el constructor de nuestro Controller recibimos como parámetro un objeto que implementa la interfaz IUserInterfaz.

Pero si ejecutamos el código sin más, recibiremos un error, porque no hay nadie proporcionando un objeto para esa interfaz. Aquí entran en juego los Contenedores de Inversión de Control (IoC, por sus siglas en inglés).
Haciendo un resumen muy somero, lo que hacen estos contenedores es tener una relación entre una interfaz y una clase que implemente esa interfaz, del tal manera, que cuando haya que "inyectar" una dependencia, sabrá perfectamente qué clase tiene que suministrar. También se encargan del ciclo de vida de estos objetos.

Hay bastantes contenedores de inversión de control (Unity, Ninject, Autofac, ...) y el concepto es el mismo en cada uno de ellos. Yo utilizo Unity (por ser el recomendado por Microsoft, razón por la que cualquier otro lo puede rechazar ;-)) y será el que veremos en los ejemplos. Concretamente he usado Unity.MVC4 que permite una integración sencilla con ASP .NET MVC4.
Ya veremos los detalles de cómo se instala y configura cuando lleguemos a la parte del cliente Web.

Bueno, dejamos estas dos entradas que han sido más de teoría que de práctica y en la próxima entramos un poco más en harina.


Un poco de lectura sobre los princios SOLID: http://www.codeproject.com/Tips/1033646/SOLID-principle-with-Csharp-example

viernes, 11 de septiembre de 2015

Inyección de dependencias

En esta entrada no pretendo dar una clase magistral o completa sobre lo que es la inyección de dependencias. Pero, por si algún intrépido lector ha llegado hasta esta entrada y quiere seguir leyendo las siguientes, recordaré el concepto de inyección de dependencias porque lo utilizaremos más adelante.

Este concepto lo utilizó hace mucho tiempo Martin Fowler y en pocas palabras lo que pretende es evitar los acoplamientos de un objeto con otro. Voy a poner un ejemplo.

Imaginemos que tenemos este controller en nuestra aplicación ASP .NET MVC.

public class LoginController : Controller
{
 public ActionResult Index(UserEntity User)
        {
            UserService UserSer = new UserService();
            UserEntity oUser;
            try
            {
                oUser = UserSer.DoLogin(User.UserName, User.Pass);
                if (oUser != null)
                {                
                    FormsAuthentication.SetAuthCookie(User.UserName, false);
                    SessionHelper.CurrentUser = oUser;
                    return RedirectToAction("Index", "History");
                }
            }
            catch (Exception ex)
            { }

            ModelState.AddModelError("", "Los datos de acceso son incorrectos.");

            return View(User);
        }

 public ActionResult Register(UserEntity User)
        {
            UserService UserSer = new UserService();
            try
            {
                oUser = UserSer.Register(User);
                return RedirectToAction("Index", "History");
            }

            catch (Exception ex)
            { }        

            return View(User);
        }
}


El controller es correcto en cuanto a la funcionalidad. Hace lo que se supone que tiene que hacer, pero podemos observar varias cosas:
- Nuestro controller está acoplado a la clase UserService.
- No cumplimos con el principio DRY (mucho código repetido)
- Difícil poder hacer pruebas unitarias a los métodos.


Vamos a hacer unos pequeños cambios para intentar mejorar la situación
public class LoginController : Controller
{
 private UserService UserSer;
 public LoginController()
{
       UserSer = new UserService();
}
 public ActionResult Index(UserEntity User)
        {          
            UserEntity oUser;
            try
            {
                oUser = UserSer.DoLogin(User.UserName, User.Pass);
                if (oUser != null)
                {                
                    FormsAuthentication.SetAuthCookie(User.UserName, false);
                    SessionHelper.CurrentUser = oUser;
                    return RedirectToAction("Index", "History");
                }
            }
            catch (Exception ex)
            { }

            ModelState.AddModelError("", "Los datos de acceso son incorrectos.");

            return View(User);
        }

 public ActionResult Register(UserEntity User)
        {
            try
            {
                oUser = UserSer.Register(User);
                return RedirectToAction("Index", "History");
            }

            catch (Exception ex)
            { }        

            return View(User);
        }
}


Bueno; hemos mejorado un poco quitando la instanciación de la clase UserService de cada método y llevándolo sólo al constructor del controller.
Pero seguimos teniendo el controller acoplado al objeto UserService y seguimos teniendo difícil el realizar pruebas unitarias debido a este acoplamiento.

Inyección de Dependencias.
Para evitar este acoplamiento utilizaremos la Inyección de Dependencias y el uso de interfaces.
Lo primero que deberemos hacer es extraer la interface de la clase UserService.
En este caso, sería algo así

public interface IUserService
    {

        UserEntity DoLogin(string Username, string Pass);
        UserEntity Register(UserEntity User);
}

Una vez hecho esto, lo que hay que decirle a la clase UserService, es que implementa esta interface.

 public class UserService : IUserService
{
/// Codigo propio de esta clase
}


Y cómo afecta esto a nuestro controller? Bien, veamos

public class LoginController : Controller
{
 private IUserInterface UserSer;
 public LoginController(IUserInterface UserServInyectado)
{
       UserSer = UserServInyectado;
}


Si nos fijamos, no queda ningún rastro de la clase UserService. Ahora solo utilizamos interfaces. Cualquier clase que implemente la interface IUserInterface será válida como parámetro del constructor de nuestro controller.

Este sistema se llama inyección de dependencias por constructor, ya que es en el constructor de nuestro objeto cuando inyectamos el "comportamiento" deseado.

¿Y quién proporciona las dependencias a nuestro controller?. Bueno eso lo veremos en la próxima entrega de Contenedores de Inversión de Control.

jueves, 10 de septiembre de 2015

Base de datos

La base de datos utilizada es SQL Server 2014. El modelo E/R es muy sencillo; se pretende guardar los movimientos que genera el usuario y poder mostrar el saldo en cada movimiento.


Este es el modelo propuesto.
Un usuario podrá generar N movimientos; los movimientos tendrán un determinado concepto que a su vez pertenece a un grupo.
Los usuarios tendrán un usuario y contraseña para acceder al sistema y serán un tipo determinado (Administrador, usuario, …)
Por ejemplo: Un usuario puede insertar un gasto en gasoil para una fecha determinada y un gasto en un restaurante para esa misma fecha.
Gasoil se podría incluir en el Grupo de Coche y la cena en el Grupo de Ocio. Es simplemente una agrupación superior de la información para hacer un estudio general.

CLAUSULA OVER
El saldo se recalcula automáticamente, bien a la hora de hacer acceder a la aplicación o bien a la hora de insertar un movimiento.
En concepto de cálculo es muy sencillo; habría que recorrer los movimientos y calcular su saldo, ya que podemos insertar movimientos en cualquier fecha.
Se podría implementar un procedimiento recursivo que fuera leyendo los importes de los movimientos anteriores.
Desde la versión de SQL Server 2005 tenemos la posibilidad de hacer sumas acumulativas utilizando la cláusula OVER con la función SUM
Este es el código que utilizamos en nuestro proyecto:
create procedure dbo.RecalculaSaldo(
       @UserName nvarchar(10))

AS
BEGIN
declare @SaldoInicial decimal(18,2);

Select @SaldoInicial = SaldoInicial From Users Where UserName = @UserName;
WITH Saldo_CTE (Id,Saldo) as (
--Recalculamos el saldo de cada movimiento
select Movimientos.id
       , @SaldoInicial + sum(importe) over (order by fechamovimiento,id) saldo
from movimientos
WHERE username =@UserName
)
--Actualizamos el saldo de cada movimiento
Update Movimientos Set Saldo = Saldo_CTE.Saldo
From Movimientos
inner join Saldo_CTE ON Saldo_CTE.Id = Movimientos.Id

END

Lo que estamos haciendo es filtrar los datos por username y ordenando por fecha e Id de movimiento. Conseguimos que la función se evalúe para cada username basándonos en la fecha y el id del movimiento.
La cláusula OVER tiene varios argumentos, pero el que más uso, junto con order by, es PARTITION, que nos permite particionar la información por una o varias columnas. En el ejemplo que vemos, no aplica porque estamos filtrando por username, pero si quisiéramos recalcular el saldo de todos los movimientos de cada uno de los usuarios, podríamos particionar la información de esta manera
select Movimientos.id
       , sum(importe) over (partition by username order by fechamovimiento,id) saldo
from movimientos

Y obtendríamos una suma acumulativa del saldo de cada usuario.


Arquitectura

Voy a dar unas breves pinceladas de la arquitectura que voy utilizar.
Voy a utilizar una arquitectura N-Capas que me permita desacoplar cada una de ellas y me dé la flexibilidad de utilizar distintos clientes en la parte de presentación.
Un esquema básico sería el de esta imagen:

Como se puede apreciar,cada capa "habla" con la inmediatamente superior o inferior utilizando Business Entitites como "idioma" común a ellas.
1. DAL
Se encarga de la persistencia y acceso a los datos. En este caso, me estoy apoyando en un ORM como EntityFramework v6.0 Code First.
Además, en esta capa se implementan Unit of Work y los repositorios
2. Services
Es la capa que tiene la lógica de la aplicación. Validaciones y reglas de negocio están aqui.
3. WebAPI
Esta capa se "superpone" a la capa de servicios para poder ofrecer una REST API que pueda ser consumida por clientes de terceros. En este caso, será consumida por una aplicación para Windows Phone 8.1
4. UI
Capa que se encarga de interactuar con el usuario. En este caso tendremos dos variables:
4.1 ASP .NET MVC4
4.2 Windows Phone
5. Business Entities
En esta capa se incluyen la entidades que serán usadas por la capa de presentación y que se usan para que ésta "hable" con la capa de servicios.
6. Infraestructura
Aquí incluyo elementos comunes (que pueden ser consumidos por cualquiera de las capas), como por ejemplo, logging, gestión de excepciones, ...

Comienzos

He decido hacer esta serie de posts para mostrar que las tecnologías, técnicas, ... que tengo en mi CV corresponden con mi experiencia. Que no lo tengo puesto para rellenar.
La solución que muestro aquí solo pretende eso y en ningún caso quiere ser una guía de cómo implementar cierta arquitectura, cómo aplicar cierta metodología o porqué usar uno u otro framework del lado de cliente, por poner varios ejemplos.
Pues al lío.
Pretendo desarrollar un sistema que te permita llevar tus cuentas. Vale, que no es muy original, que ya te da la información del banco,... pero bueno, se puede ver cómo crear acciones CRUD en una sola vista.
Puestos a poner requerimientos, que se pueda trabajar desde un dispositivo móvil; en principio, solo estará disponible para Windows Phone, pero según vaya avanzando .... veremos.
Pues para realizar este proyecto voy a usar .NET. Concretamente:
  • Unit of Work
  • Repository Pattern
  • ASP .NET MVC 4
  • C#
  • WebAPI
  • MVVM con Knockout
  • jQuery 1.9.1
  • jQueryUI 1.11.4
  • jQuery Validation Plugin
  • Toastr 
  • Bootstrap 3.3.5
  • Entity Framework 6 Code First
  • SQL Server 2014

En la siguiente entrada publicaré la arquitectura que he usado.