lunes, 16 de abril de 2012

Registrando los cambios de nuestros objectos en Entity Framework (II)

En mi anterior artículo sobre como registrar cambios de nuestros objetos en el Entity Framework dejé sin terminar una parte. En concreto, la parte en la que obtendríamos el IdResource en nuestro TrackFactory.

La primera alternativa que utilice fue la siguiente
private Track TrackFactory(ObjectStateEntry entry)
{
 Track track = new Track();
 track.IdTrack = Guid.NewGuid();
 track.TableName = entry.EntitySet.Name;
 track.FC = DateTime.Now;
 track.UC = string.Empty;

 if (entry.State == EntityState.Added)
 {
  // Insert (I)
  track.IdResource = entry.EntityKey.EntityKeyValues[0].Value.ToString();  
  track.NewData = this.GetXml(entry, false);
  track.Action = TrackActionsEnum.I.ToString();
 }
 else if (entry.State == EntityState.Deleted)
 {
  // Update (U)
  track.IdResource = entry.EntityKey.EntityKeyValues[0].Value.ToString();
  track.OldData = this.GetXml(entry, true);
  track.NewData = this.GetXml(entry, false);
  track.Action = TrackActionsEnum.U.ToString();
 }
 else
 {
  // Delete (D)
  track.IdResource = entry.EntityKey.EntityKeyValues[0].Value.ToString();
  track.OldData = this.GetXml(entry, true);
  track.Action = TrackActionsEnum.D.ToString();
 }

 return track;
}
Esta solución hubiera sido fantástica salvo porque no funciona a la hora de obtener el identificador en la inserción de un registro, ya que EntityKey es nulo. Tras darle varias vueltas al asunto la única posibilidad que me quedó fue recorrer por reflexión todas las propiedades del objeto y detectar aquella que tuviera el atributo EdmScalarPropertyAttribute definido y la propiedad EntityKeyProperty a true. Al final el código no queda muy largo y es el siguiente
private string GetIdResource(ObjectStateEntry entry) {
 object entity = entry.Entity;

 PropertyInfo[] properties = entity.GetType().GetProperties();
  foreach (PropertyInfo pi in properties)
  {
  System.Object[] attributes = pi.GetCustomAttributes(true);
  foreach (object attribute in attributes)
    {
   if (attribute is EdmScalarPropertyAttribute)
    if (((EdmScalarPropertyAttribute)attribute).EntityKeyProperty == true)
     return pi.GetValue(entity, null).ToString();
  }
 }

 return null;
}
Por lo que el método TrackFactory quedo así al final
private Track TrackFactory(ObjectStateEntry entry)
{
        // ...
 if (entry.State == EntityState.Added)
 {
  // Insert (I)
  track.IdResource = this.GetIdResource(entry); 
  track.NewData = this.GetXml(entry, false);
  track.Action = TrackActionsEnum.I.ToString();
 }
        // ...
}
Con esta mejora es fácil hacer el seguimiento a nuestros cambios. Por ejemplo con este código
using (DataContext context = new DataContext())
{
 // Insertamos una películas
 context.AddToPelicula(new Pelicula() { IdPelicula = 1, Titulo = "El padrino", Sinopsis = "...", Calificacion = 10 });
 context.SaveChanges();
    
 // Modificamos la película
 Pelicula p1 = context.Pelicula.Where(m => m.IdPelicula == 1).Single();
 p1.Calificacion = 9;
 context.SaveChanges();

 p1 = context.Pelicula.Where(m => m.IdPelicula == 1).Single();
 p1.Calificacion = 10;
 context.SaveChanges();

 // Borramos la película
 p1 = context.Pelicula.Where(m => m.IdPelicula == 1).Single();
 context.Pelicula.DeleteObject(p1);
 context.SaveChanges();
}
Sería fácil (sabiendo el Id que tenía la película en la base de datos, ver la secuenda de la vida del registro en la base de datos como vemos en nuestra tabla.


En la próxima entrega intentaré resolver de una forma "no muy elegante" (pero tampoco he encontrado otra) el caso de la inserciones de registros donde el Id es un identity, por lo que no conocemos el valor del Id antes de grabar. Lo que nos llevará a tener que grabar todos nuestros objectos en la base de datos para posteriormente grabar el registro de cambios.

Happy coding!

 Mas Info | Registrar cambios en nuestros objecto en el Entity Framework (I)

No hay comentarios:

Publicar un comentario