2010-01-16 11 views
3

J'ai créé 3 tables dans ma base de données et y ai placé des données. Les 3 tables ont toutes des clés étrangères qui les joignent. Voici les classes de table et les mappings. Quand je lance la requête listée à la fin, j'obtiens IList <> des objets et ils ont les données des 3 tables. Cependant, ma requête HQL est uniquement à partir du tableau le plus haut. Comment puis-je récupérer seulement les résultats de la plus haute table?Obtenir des données de toutes les tables au lieu d'une seule avec la requête HQL qui ne doit recevoir que les données d'une table

Ce sont mes classes:

public class Technology 
{ 
    public virtual int Id { get; private set; } 
    public virtual string Name { get; set; } 
    public virtual int SortOrder { get; set; } 
    public virtual string Abbreviation { get; set; } 
    public virtual IList<TechnologyDescription> TechnologyDescriptions { get; private set; } 

    public Technology() 
    { 
     TechnologyDescriptions = new List<TechnologyDescription>(); 
    } 

    public virtual void AddTechnologyDescription(TechnologyDescription technologyDescription) 
    { 
     technologyDescription.Technology = this; 
     TechnologyDescriptions.Add(technologyDescription); 
    } 
} 

public class TechnologyDescription 
{ 
    public virtual int Id { get; private set; } 
    public virtual Technology Technology { get; set; } 
    public virtual string Description { get; set; } 
    public virtual DescriptionType DescriptionType { get; set; } 
} 

public class DescriptionType 
{ 
    public virtual int Id {get; private set;} 
    public virtual string Type { get; set; } 
} 

These are my mapping objects: 

public class TechnologyMap : ClassMap<Technology> 
{ 
    public TechnologyMap() 
    { 
     Id(x => x.Id); 
     Map(x => x.Name); 
     Map(x => x.SortOrder); 
     Map(x => x.Abbreviation); 
     HasMany(x => x.TechnologyDescriptions) 
       .Inverse() 
       .Cascade.All(); 
    } 
} 

public class TechnologyDescriptionMap : ClassMap<TechnologyDescription> 
{ 
    public TechnologyDescriptionMap() 
    { 
     Id(x => x.Id); 
     References(x => x.Technology); 
     Map(x => x.Description); 
     References(x => x.DescriptionType); 
    } 
} 

public class DescriptionTypeMap : ClassMap<DescriptionType> 
{ 
    public DescriptionTypeMap() 
    { 
     Id(x => x.Id); 
     Map(x => x.Type); 
    } 
} 

Et voici mon code HQL:

IQuery q = session.CreateQuery("from Technology T"); 
IList technologies = q.List(); 
+0

Merci à vous deux. Vos réponses m'ont aidé. Merci! –

Répondre

1

Je ne sais pas s'il est possible à l'aide HQL, mais en utilisant l'API de critères de NHibernate, vous pouvez faites ceci:

ICriteria criteria = session.CreateCriteria (typeof(Technology)); 

criteria.SetFetchMode ("TechnologyDescriptions", FetchMode.Lazy); 

var list = criteria.List<Technology>(); 

Cependant, ce n'est probablement pas vraiment ce que vous voulez. Les descriptions technologiques ne seront pas récupérées pour le moment, mais elles seront récupérées dès que vous y accéderez (c'est-à-dire: la première fois que vous appelez la propriété TechnologyDescriptions). Lorsque vous travaillez avec NHibernate, vous ne devriez pas penser en termes de 'données'. Au contraire, vous devriez penser en termes d '«entités».
Lors de la récupération d'une entité, vous voulez récupérer l'entité entièrement (directement, ou paresseusement). Il n'est pas possible de récupérer partiellement une entité, ce qui est assez évident; Que devrait faire NHibernate avec une entité que vous avez récupérée partiellement, lorsque vous essayez de sauvegarder cette entité?

Quelque chose d'autre qui apparaît dans mon esprit: Je suppose que vous voulez récupérer les technologies, et rien de lié parce que vous voulez les afficher dans un aperçu ou quelque chose comme ça? Dans ce cas, vous devriez jeter un oeil à 'Transformations'. Vous pouvez par exemple créer une classe supplémentaire qui est appelé TechnologyView, qui ressemble à ceci:

public class TechnologyView 
{ 
    public int Id 
    { 
     get; 
     private set; 
    } 

    public string Name 
    { 
     get; 
     private set; 
    } 

    public string Abbreviation 
    { 
     get; 
     private set; 
    } 

    private TechnologyView() 
    { 
     // Private constructor, required for NH 
    } 

    public TechnologyView(int id, string name, string abbreviation) 
    { 
     this.Id = id; 
     this.Name = name; 
     this.Abbreviation = abbreviation; 
    } 
} 

Une fois que vous avez fait cela, vous devez en informer NHibernate sur l'existance de cette classe. Vous faites cela en Important la classe dans un fichier hbm.xml par exemple. (Je ne sais pas comment le faire en utilisant Fluent).

<import class="MyNamespace.TechnologyView" /> 

Après cela, vous pouvez créer une requête (en utilisant HQL ou critères) qui récupère les instances TechnologyView. NHibernate est assez intelligent pour générer une requête SQL performante.

utilisant HQL:

IQuery q = s.CreateQuery ("select new TechnologyView (t.Id, t.Name, t.Abbreviation) from Technology t"); 

en utilisant des critères:

ICriteria criteria = s.CreateCriteria (typeof(Technology)); 
criteria.SetResultTransformer (Transformers.AliasToBean (typeof(TechnologyView)); 
var result = criteria.List<TechnologyView>(); 
+0

Cela aide donc. Une chose que je veux clarifier et peut-être c'est où je me perds. La raison pour laquelle je ne voulais pas toutes les données dans la table de description de technologie pour chacune de mes technologies était parce que certaines des descriptions ne seraient pas pertinentes pour la page sur laquelle je suis. Cependant, si je vous comprends bien, je voudrais supprimer/ignorer ces résultats à travers la façon dont je parcours l'entité technologique. Cela me semble étrange, car cela signifierait qu'il n'y a aucune raison pour les chaînes de Query car tout serait fait après cela. –

+0

Je ne comprends pas vraiment votre commentaire. Si vous n'avez pas besoin des descriptions sur la page que vous utilisez, j'opterais pour l'approche 'Transformations'. –

1

Je pense que ce que vous cherchez est pour les TechnologyDescriptions être paresseux chargé. De cette façon, les descriptions ne sont chargées à partir de la base de données que lorsqu'elles sont accédées (NHibernate émettra une seconde requête db.) Notez que cela peut entraîner des sélections N + 1 dans certaines situations et vous pouvez préférer la requête tout à la fois.

Par NHibernate, les mappages XML effectuent un chargement paresseux de collections. Dans le passé, il semble que le Fluent NHibernate n'avait pas le même défaut.Vous devez ajouter .LazyLoad() au mappage.

Récemment, il semble comme le chargement paresseux est devenu la valeur par défaut mappage couramment: Is the default behavior with Fluent NHibernate to lazy load HasMany<T> collections?