Puis-je utiliser des critères de NHibernate pour projeter une entité et sa collection enfant sur une classe?

StackOverflow https://stackoverflow.com/questions/4977038

Question

J'utilise des critères NH pour récupérer une entité et des champs sélectifs de projet sur une classe personnalisée (un peu comme des données de saillie sur une vue de vue pour afficher sur une vue MVC).

Ceci est assez facile à l'aide de la projection de projection:

var emailCriteria = mSession.CreateCriteria<Email>();
emailCriteria.SetProjection(
    Projections.ProjectionList()
        .Add(Projections.Property("Subject"), "Subject")
);
emailCriteria.SetResultTransformer(Transformers.AliasToBean<EmailDataModel>());
var result = emailCriteria.List<EmailDataModel>();

Cependant, mon entité contient une collection et je tiens à reporter cela aussi, et à la projette comme une collection sur ma classe personnalisée.

Mon modèle de domaine semble (sous formulaire simplifié) comme ceci:

public class Email {
    public string Subject
    public List<EmailAttachment> Attachments
    etc...
}

public class EmailAttachment {
    public UploadedFile File
}

public class UploadedFile {
    public string Filename
    public UploadedFileData Data
}

public class UploadedFileData {
    public byte[] Data
}

Voici les classes "Modèle de données" que je souhaite projeter sur:

public class EmailDataModel {
    public string Subject
    public List<EmailAttachmentDataModel> Attachments
}

public class EmailAttachmentDataModel {
    public string Filename
    public byte[] Data
}

Maintenant, je sais que ces modèles semblent très similaires, et vous seriez pardonné de penser "quel est le point?", mais c'est parce que je les ai simplifiées. C'est bien de pouvoir aplatir mes objets de domaine dans des modèles de données utiles.

Mon gros problème consiste à déterminer comment accéder aux champs nécessaires du fond des objets de mon enfant (dans ce cas, surploadedfile.filename et uploadedfiledata.data) et projetez-les comme une collection de messagerieTatachmentDatamodel sur mon courrier électronique.

J'ai lu beaucoup d'articles en ligne qui discutent d'accéder à des collections d'enfants - en utilisant soi-même un courrielcriteria.createalias ou un courrielcriteria.creequace - mais je n'ai rien trouvé qui explique comment projeter une collection d'enfants en tant que collection.

J'espère que ce sera un exercice utile pour quiconque intéressé par Tinkering avec les requêtes de critères NH.

Était-ce utile?

La solution

OK, je pense que j'ai résolu cette mise à niveau vers NHibernate 3 et utiliser la requérante. Voici ce que mon code ressemble maintenant à:

//Declare entities
Email email = null;
EmailAttachment attachment = null;
UploadedFile file = null;
Byte[] fileData = null;

//Select data from parent and child objects
var results = mSession.QueryOver<QueuedEmail>(() => email)
   .JoinAlias(() => email.Attachments, () => attachment, JoinType.LeftOuterJoin)
   .JoinAlias(() => attachment.File, () => file, JoinType.LeftOuterJoin)
   .JoinAlias(() => file.Data, () => fileData, JoinType.LeftOuterJoin)
   .TransformUsing(Transformers.DistinctRootEntity)
   .List<Email>()

   //Loop through results projecting fields onto POCO
   .Select(x => new EmailDataModel()
   {
       Id = x.Id,
       Body = x.Body,
       AttachmentCount = x.Attachments.Count(),
       FromAddress = x.FromAddress,
       //Loop through child collection projecting fields onto POCO
       Attachments = x.Attachments.Select(attach => new EmailAttachmentDataModel()
       {
           Data = attach.File.Data.Data,
           Filename = attach.File.Filename,
           Id = attach.Id
       }).ToArray() //NB Now projecting this collection as an array, not a list
   }).ToArray();

donc là-bas c'est. Notre résultat est une classe aplatie contenant les données dont nous avons besoin, plus une collection de pièces jointes (qui contiennent chacune deux champs de notre structure de données - bien aplati).

Pourquoi devriez-vous faire cela?

  1. Il simplifie le résultat en aplatissant uniquement les champs que je veux vraiment.

  2. Mes données sont désormais encapsulées en toute sécurité dans une classe qui peut être transmise sans crainte de mettre à jour accidentellement mes données (ce qui pourrait arriver si vous passez simplement des entités de données NH).

  3. Enfin (et surtout), car le code ci-dessus génère uniquement une instruction SELECT. Si je suis resté coincé avec ma requête de critère d'origine, il aurait généré une sélection pour chaque ligne, plus pour les enfants plus loin dans la chaîne. C'est bien si vous traitez de petits chiffres, mais pas si vous retournez potentiellement des milliers de lignes (comme je le ferai dans ce cas, c'est un service Web pour un moteur de messagerie).

    J'espère que cela a été utile pour quiconque souhaitant pousser un peu plus loin dans NHibernate Interrogation. Personnellement, je suis juste heureux que je puisse maintenant continuer avec ma vie!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top