Hola Pablo,

2015-04-30 16:46 GMT-03:00 Pablo Leiros <bl4...@gmail.com>:

> Hola a todos!
>
> Les presento mi problema que debe ser muy parecido a otros problemas de
> serializacion como el en caso de serializar JSON. En mi caso, tengo el
> problema de que tengo que realizar una exportación de una lista de
> entidades a XML y cuando quiero realizarla tuve que hacer un par de
> *walkarounds* para poder realizar algo cercano sin tener que caer en los
> DTOs ya que, a futuro, voy a estar duplicando todo el dominio para poder
> serializar.
>

En mi experiencia esto es una simplificación peligrosa. De hecho, ya estas
sufriendo los efectos de esa simplificación con las dificultades de
serializar. Estas imponiendo a tus objetos del dominio una necesidad
adicional que ahora te impone dificultades las cuales solo pueden aumentar
en el futuro.

Ademas, cuando usas DTOs, la idea es interactuar con un sistema externo. Me
imagino que vas a tener que hacer muchos malabarismos en el futuro para
poder cambiar tus objetos de dominio sin cambiar esa interfaz con el
sistema externo.

Puede que tengas el control de ese sistema externo pero, aun así es un
problema que un cambio en el dominio impacte a otros subsistemas. Tarde o
temprano dejaras los cambios para mas tarde (deuda técnica) por el impacto
que tendrán.

Por el lado de la duplicación, en mi experiencia no es así. Cuando tenes la
posibilidad de pensar los DTOs en forma separada del modelo del dominio,
rápidamente encontrás caminos divergentes que te permiten optimizaciones en
ambos lados (lazy loading en el dominio y objetos mas pequeños y eficientes
en la interfaz)

Sugiero que pienses en esto antes de proseguir por este camino.

*Historia:*
>
> De primera, intente serializar a XML de una pero me tope con que no se
> puede serializar interfaces. Entonces, investigando un poco caí en este
> tema de StackOverflow donde aparece el primer walkaround: Xml
> Deserialization with Proxy
> <http://stackoverflow.com/questions/14225568/xml-deserialization-with-proxy>
> Implemente el walkaround pero me siguió molestando con una
> ProxyAccesException donde me dice, en resumen, que no puede convertir un
> PersistentBag a List<T>. Eso me lo tira en el repositorio genérico para NH
> que tengo incluido aca..
> Mirando el mapping no encontré en ningún lado que haya mapeado un List<T>,
> ademas, NH no te lo permite realizar. Entonces, mirando en profundidad,
> únicas propiedades que retornan un List<T> son las la que surrogan las
> listas cuando se serializa a XML.
> El tema acá es que no están mapeadas esas listas, por ende, el mapping
> debería ignorar estas propiedades. Y lo peor de todo, es que la excepción
> que me tira es a causa de esto.
> Entonces, busque una manera de que ignore a mano las propiedades pero nada
> (Ignoring methods on entity types with nHibernate
> <http://stackoverflow.com/questions/1120574/ignoring-methods-on-entity-types-with-nhibernate>
> ).
>
> Sigo leyendo otras cosas por las cuales puede resolver y "deshabilite" el
> lazyload de la entidad y los de los bags. También encontré una magia para
> desproxificar las entidades (Hacking lazy loaded inheritance
> <http://sessionfactory.blogspot.com.ar/2010/08/hacking-lazy-loaded-inheritance.html>
>  y WCF + NHibernate: Entity Serialization
> <http://nhibernate.info/doc/howto/various/wcf-nhibernate-entity-serialization.html>)
> pero nada...
>
> Acá les dejo el código necesario para que puedan ver donde puede haber una
> solución para esto. Si necesitan revisar mas en profundidad, les dejo el
> repositorio de github: escuela-simple
> <https://github.com/drielnox/escuela-simple>
>
> *Entidad:*
>
> namespace EscuelaSimple.Modelos
> {
>     [Serializable()]
>     public class Personal : IEntidad<uint>
>     {
>         [XmlAttribute]
>         public virtual uint Identificador { get; set; }
>         public virtual string Nombre { get; set; }
>         public virtual string Apellido { get; set; }
>         public virtual uint DNI { get; set; }
>         public virtual DateTime FechaNacimiento { get; set; }
>         public virtual string Domicilio { get; set; }
>         public virtual string Localidad { get; set; }
>         [XmlIgnore]
>         public virtual ICollection<Telefono> Telefonos { get; protected set; }
>         [XmlElementAttribute(IsNullable = true)]
>         public virtual DateTime? IngresoDocencia { get; set; }
>         [XmlElementAttribute(IsNullable = true)]
>         public virtual DateTime? IngresoEstablecimiento { get; set; }
>         public virtual string Titulo { get; set; }
>         public virtual string Cargo { get; set; }
>         public virtual string SituacionRevista { get; set; }
>         public virtual string Observacion { get; set; }
>         [XmlIgnore]
>         public virtual ICollection<Inasistencia> Inasistencias { get; 
> protected set; }
>
>         public Personal()
>         {
>             this.Telefonos = new List<Telefono>();
>             this.Inasistencias = new List<Inasistencia>();
>         }
>
>         public void AgregarTelefono(Telefono telefono)
>         {
>             if (!this.Telefonos.Contains(telefono))
>             {
>                 this.Telefonos.Add(telefono);
>             }
>         }
>
>         public void QuitarTelefono(Telefono telefono)
>         {
>             if (this.Telefonos.Contains(telefono))
>             {
>                 this.Telefonos.Remove(telefono);
>             }
>         }
>
>         public void AgregarInasistencia(Inasistencia inasistencia)
>         {
>             if (!this.Inasistencias.Contains(inasistencia))
>             {
>                 this.Inasistencias.Add(inasistencia);
>             }
>         }
>
>         public void QuitarInasistencia(Inasistencia inasistencia)
>         {
>             if (this.Inasistencias.Contains(inasistencia))
>             {
>                 this.Inasistencias.Remove(inasistencia);
>             }
>         }
>
>         #region Surrogacion para XMLSerializer
>
>         [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
>         [XmlArray(ElementName = "Telefonos"), XmlArrayItem("Telefono", 
> typeof(Telefono))]
>         public virtual List<Telefono> ListaDeTelefonosSurrogado
>         {
>             get
>             {
>                 List<Telefono> proxy = this.Telefonos as List<Telefono>;
>                 if (proxy == null && this.Telefonos != null)
>                 {
>                     proxy = (List<Telefono>)this.Telefonos;
>                 }
>
>                 return proxy;
>             }
>             set
>             {
>                 this.Telefonos = value;
>             }
>         }
>
>         [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
>         [XmlArray(ElementName = "Inasistencias"), 
> XmlArrayItem("Inasistencia", typeof(Inasistencia))]
>         public virtual List<Inasistencia> ListaDeInasistenciasSurrogada
>         {
>             get
>             {
>                 List<Inasistencia> proxy = this.Inasistencias as 
> List<Inasistencia>;
>                 if (proxy == null && this.Inasistencias != null)
>                 {
>                     proxy = (List<Inasistencia>)this.Inasistencias;
>                 }
>
>                 return proxy;
>             }
>             set
>             {
>                 this.Inasistencias = value;
>             }
>         }
>
>         #endregion
>
>         #region Sobrecarga a Object
>
>         public override bool Equals(object obj)
>         {
>             if (obj == null)
>             {
>                 return false;
>             }
>
>             Personal personal = obj as Personal;
>             if (personal == null)
>             {
>                 return false;
>             }
>
>             return this.Identificador.Equals(personal.Identificador) &&
>                 this.Nombre.Equals(personal.Nombre) &&
>                 this.Apellido.Equals(personal.Apellido) &&
>                 this.DNI.Equals(personal.DNI) &&
>                 this.FechaNacimiento.Equals(personal.FechaNacimiento);
>         }
>
>         public override int GetHashCode()
>         {
>             string hashCode = this.Identificador + "|" + this.Nombre + "|" + 
> this.Apellido + "|" +
>                 this.DNI + "|" + this.FechaNacimiento + "|" + this.Domicilio 
> + "|" +
>                 this.Localidad + "|" + this.Telefonos + "|" + 
> this.IngresoDocencia + "|" +
>                 this.IngresoEstablecimiento + "|" + this.Titulo + "|" + 
> this.Cargo + "|" +
>                 this.SituacionRevista + "|" + this.Observacion + "|" + 
> this.Inasistencias;
>             return hashCode.GetHashCode();
>         }
>
>         #endregion
>     }
> }
>
>
> Mapping:
>
> namespace EscuelaSimple.Datos.Mapeo.NHibernate
> {
>     public class PersonalMap : ClassMapping<Personal>
>     {
>         public PersonalMap()
>         {
>             Lazy(false);
>
>             Table("Personal");
>
>             Id<uint>(x => x.Identificador, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("IdPersonal");
>                 m.Generator(Generators.Identity);
>             });
>
>             Property<string>(x => x.Nombre, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("Nombre");
>                 m.NotNullable(true);
>             });
>             Property<string>(x => x.Apellido, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("Apellido");
>                 m.NotNullable(true);
>             });
>             Property<uint>(x => x.DNI, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("DNI");
>                 m.UniqueKey("UK_Personal_DNI");
>                 m.NotNullable(true);
>             });
>             Property<DateTime>(x => x.FechaNacimiento, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("FechaNacimiento");
>                 m.NotNullable(true);
>                 m.Type<DateType>();
>             });
>             Property<string>(x => x.Domicilio, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("Domicilio");
>                 m.NotNullable(false);
>             });
>             Property<string>(x => x.Localidad, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("Localidad");
>                 m.NotNullable(false);
>             });
>             Property<DateTime?>(x => x.IngresoDocencia, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("IngresoDocencia");
>                 m.NotNullable(false);
>                 m.Type<DateType>();
>             });
>             Property<DateTime?>(x => x.IngresoEstablecimiento, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("IngresoEstablecimiento");
>                 m.NotNullable(false);
>                 m.Type<DateType>();
>             });
>             Property<string>(x => x.Titulo, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("Titulo");
>                 m.NotNullable(false);
>             });
>             Property<string>(x => x.Cargo, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("Cargo");
>                 m.NotNullable(false);
>             });
>             Property<string>(x => x.SituacionRevista, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("SituacionRevista");
>                 m.NotNullable(false);
>             });
>             Property<string>(x => x.Observacion, m =>
>             {
>                 m.Access(Accessor.Property);
>                 m.Column("Observacion");
>                 m.NotNullable(false);
>             });
>
>             Set<Telefono>(x => x.Telefonos,
>                 cm =>
>                 {
>                     cm.Access(Accessor.Property);
>                     cm.Table("Telefono");
>                     cm.Key(k =>
>                     {
>                         k.Column(c =>
>                         {
>                             c.Name("IdPersonal");
>                             c.NotNullable(true);
>                             c.UniqueKey("UK_Telefono_2");
>                         });
>                         k.ForeignKey("FK_Telefono_Personal_1");
>                         k.NotNullable(true);
>                     });
>                     cm.Cascade(Cascade.All);
>                     cm.Lazy(CollectionLazy.NoLazy);
>                 },
>                 m =>
>                 {
>                     m.OneToMany(x =>
>                     {
>                         x.Class(typeof(Telefono));
>                         x.NotFound(NotFoundMode.Exception);
>                     });
>                 });
>             Set<Inasistencia>(x => x.Inasistencias,
>                 cm =>
>                 {
>                     cm.Access(Accessor.Property);
>                     cm.Table("Inasistencia");
>                     cm.Key(k =>
>                     {
>                         k.Column(c =>
>                         {
>                             c.Name("IdPersonal");
>                             c.NotNullable(true);
>                         });
>                         k.ForeignKey("FK_Inasistencia_Personal_1");
>                         k.NotNullable(true);
>                     });
>                     cm.Cascade(Cascade.All);
>                     cm.Lazy(CollectionLazy.NoLazy);
>                 },
>                 m =>
>                 {
>                     m.OneToMany(x =>
>                     {
>                         x.Class(typeof(Inasistencia));
>                         x.NotFound(NotFoundMode.Exception);
>                     });
>                 });
>         }
>     }
> }
>
>
> *Repositorio generico para NH:*
>
> namespace EscuelaSimple.Datos.Repositorio
> {
>     public abstract class NHibernateRepositorio<TEntidad, TClavePrimaria> : 
> IRepositorio<TEntidad, TClavePrimaria>
>         where TEntidad : class, IEntidad<TClavePrimaria>
>         where TClavePrimaria : struct
>     {
>         public ISession Sesion { get; set; }
>
>         public NHibernateRepositorio(ISession sesion)
>         {
>             this.Sesion = sesion;
>         }
>
>         public TEntidad ObtenerPorIdentificador(TClavePrimaria id)
>         {
>             return this.Sesion.Get<TEntidad>(id);
>         }
>
>         public IEnumerable<TEntidad> ObtenerTodo()
>         {
>             IQueryOver<TEntidad> result = this.Sesion.QueryOver<TEntidad>();
>             return result.List(); // <<< Aca tira ProxyAccessException!!!
>         }
>
>         public void Crear(TEntidad entity)
>         {
>             this.Sesion.Save(entity);
>         }
>
>         public void Actualizar(TEntidad entity)
>         {
>             this.Sesion.Update(entity);
>         }
>
>         public void Borrar(TEntidad entity)
>         {
>             this.Sesion.Delete(entity);
>         }
>
>         public TEntidad ObtenerPor(Predicate<TEntidad> predicate)
>         {
>             List<TEntidad> result = this.FiltrarPor(predicate) as 
> List<TEntidad>;
>             return result.Count > 0 ? result[0] : null;
>         }
>
>         public IEnumerable<TEntidad> FiltrarPor(Predicate<TEntidad> predicate)
>         {
>             List<TEntidad> result = this.ObtenerTodo() as List<TEntidad>;
>             return result.FindAll(predicate);
>         }
>     }
> }
>
>
>
>
>
>
>
>  --
> --
> Para escribir al Grupo, hágalo a esta dirección:
> NHibernate-Hispano@googlegroups.com
> Para más, visite: http://groups.google.com/group/NHibernate-Hispano
> ---
> Has recibido este mensaje porque estás suscrito al grupo
> "NHibernate-Hispano" de Grupos de Google.
> Para anular la suscripción a este grupo y dejar de recibir sus mensajes,
> envía un correo electrónico a
> nhibernate-hispano+unsubscr...@googlegroups.com.
> Para acceder a más opciones, visita https://groups.google.com/d/optout.
>

-- 
-- 
Para escribir al Grupo, hágalo a esta dirección: 
NHibernate-Hispano@googlegroups.com
Para más, visite: http://groups.google.com/group/NHibernate-Hispano
--- 
Has recibido este mensaje porque estás suscrito al grupo "NHibernate-Hispano" 
de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía 
un correo electrónico a nhibernate-hispano+unsubscr...@googlegroups.com.
Para obtener más opciones, visita https://groups.google.com/d/optout.

Responder a