7
votes

Comment puis-je sérialiser toutes les propriétés d'un objet mappé de NHibernate?

J'ai des méthodes Web qui renvoient mes objets en tant que XML sérialisé. Serialiser uniquement les propriétés cartographiées de NHibernate de l'objet ... Tout le monde a une idée? Il semble que les méthodes Web soient en train de sérialiser les proxies NHibernate au lieu de mes classes. J'ai essayé d'utiliser [xmlinclude] et [xmlelement], mais les propriétés ne sont toujours pas sérialisées. J'ai une façon vraiment horrible de me déplacer, mais je me demandais s'il y avait une meilleure façon!

Quelque chose comme ceci: p>

<?xml version="1.0" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="StoryManager" assembly="StoryManager">
  <class name="Graphic" table="graphics" lazy="false">
    <id name="Id" column="id" type="int" unsaved-value="0" >
      <generator class="identity"/>
    </id>

    <property name="Assigned" />
    <property name="Due" />
    <property name="Completed" />
    <property name="UglyHack" insert="false" update="false" />


    <many-to-one name="Parent" class="Story" column="story_id"/>

  </class>
</hibernate-mapping>

public class Graphic
{
    private int m_id;
    public virtual int Id
    {
        get { return m_id; }
        set { m_id = value; }
    }

    private DateTime? m_assigned;
    public virtual DateTime? Assigned
    {
        get { return m_assigned; }
        set { m_assigned = value; }
    }

    private DateTime? m_due;
    public virtual DateTime? Due
    {
        get { return m_due; }
        set { m_due = value; }
    }

    private DateTime? m_completed;
    public virtual DateTime? Completed
    {
        get { return m_completed; }
        set { m_completed = value; }
    }

    public bool UglyHack
    {
        get { return m_due < m_completed; } // return something besides a real mapped variable
        set {} // trick NHibernate into thinking it's doing something
    }
}


0 commentaires

3 Réponses :


21
votes

Le meilleur moyen de sérialiser l'objet mappé NH est de ne pas le sérialiser :).

Si vous l'envoyez sur le fil, vous devez vraiment créer un DTO pour cela. Si vous ne voulez pas créer cet objet, vous pouvez définir [xmlignore] sur les propriétés que vous ne voulez pas sérialiser.

Si vous voulez toutes les propriétés, vous devez les charger tous de la base de données - car une charge désireuse suffira à d'autres (où trop de jointures commenceront à dupliquer les données), vous devrez accéder à cette propriété de quelque manière que ce soit. Vous voulez déclencher la charge.

EDIT:

Et j'aimerais ajouter une autre chose - envoyer vos entités de domaine sur le fil est toujours une mauvaise idée. Dans mon cas, j'en ai appris la solution difficile - j'expose certaines entités sur un service Web - et presque tout changement (renommer une propriété, supprimer une propriété ..etc) à mon domaine tue l'application à l'aide de la WS - plus un tas de les propriétés ont [xmlignore] sur eux (n'oubliez pas de dépendances circulaires).

Nous ferons une réécriture suffisamment de temps - mais vous assure que ce n'est pas quelque chose que je vais jamais faire à nouveau. :)

EDIT 2

Vous pouvez utiliser Automapper pour transférer les données de votre entité vers le DTO. Ils ont quelques exemples sur le site.


1 commentaires

Je vois ton point :) Maintenant, j'essaie juste de comprendre comment les générer à réflexion ...



0
votes

D'accord avec Sirrocco, j'ai eu le temps le plus affreux qui tente de sérialiser les entités de NHibernate à travers la WCF et devenue éventuellement une solution DTO effectuée de manière générique par réflexion.

Edit: Toute la solution est trop grande pour poster ici, et est personnalisé pour mes besoins de succès, donc je posterai quelques sections pertinentes: p> xxx pré>

puis, lorsque vous souhaitez ressusciter le DTO: P>

    private static DTOConversionResults ConvertDTOToEntity(DataTransferObject transferObject,object parent)
    {
        DTOConversionResults conversionResults = new DTOConversionResults();

        object baseEntity = null;
        ObjectHandle entity = Activator.CreateInstance(transferObject.AssemblyName,
                                                       transferObject.TransferType);

        if (entity != null)
        {
            baseEntity = entity.Unwrap();

            conversionResults.Add(UpdatePrimaryKeyValue(transferObject, baseEntity));
            conversionResults.Add(UpdateFieldValues(transferObject, baseEntity));
            conversionResults.Add(UpdatePropertyValues(transferObject, baseEntity));
            conversionResults.Add(UpdateSubEntitiesValues(transferObject, baseEntity));
            conversionResults.Add(UpdateRelatedEntitiesValues(transferObject, baseEntity,parent));
....

    private static DTOConversionResult UpdatePropertyValues(DataTransferObject transferObject, object entity)
    {            
        DTOConversionResult conversionResult = new DTOConversionResult();

        foreach (KeyValuePair<string, object> values in transferObject.PropertyValues)
        {
            try
            {
                ReflectionHelper.SetPropertyValue(entity, values.Key, values.Value);
            }
            catch (Exception ex)
            {
                string failureReason = "Failed to set property " + values.Key + " value " + values.Value;

                conversionResult.Failed = true;
                conversionResult.FailureReason = failureReason;

                Logger.LogError(failureReason);
                Logger.LogError(ExceptionLogger.BuildExceptionLog(ex));
            }
        }

        return conversionResult;
    }


1 commentaires

Ne sera-t-il pas automappé cette tâche?



4
votes

Si son service WCF, vous pouvez utiliser une implémentation IDataContractSurrogate xxx

dans l'hôte: xxx


0 commentaires