4

J'ai une table mappée dans NHibernate Fluent. Cette table doit se joindre à une autre table sur un ID, mais doit également filtrer les valeurs jointes sur cette table par rapport à un ensemble de valeurs constantes. Considérez l'instruction SQL suivante:Fluent NHibernate Références avec constantes

SELECT * 
FROM 
    Table1 
INNER JOIN 
    Table2 ON 
    Table1.Table2Id = Table2.Id 
    AND Table2.Category = 'A constant expression' 
    AND Table2.Language = 'A constant expression' 

Ma carte couramment pour Tableau1 ressemble actuellement à ceci:

References(a => a.Table2).Nullable().Columns("Table2Id").ReadOnly(); 

Comment puis-je mettre en œuvre les expressions constantes?

Répondre

1

J'ai remarqué que votre mappage spécifiait Nullable et aucune récupération désirée (par défaut, il sera chargé paresseux).Donc si vous vouliez générer le sql que vous avez montré dans votre commentaire, vous ne seriez pas capable de le faire avec un simple session.Get<Table1>(). Même si vous avez modifié le mappage de sorte qu'il était comme ça:

References(a => a.Table2).Nullable().Columns("Table2Id").ReadOnly().Fetch.Join; 

Vous très probablement avec une jointure externe gauche dans le sql en sortie. La seule façon de forcer une extraction avec une jointure interne (sans télécharger d'extension supplémentaire de NHibernate) serait d'utiliser un session.QueryOver (vous pouvez aussi le faire avec session.Query et les extensions NHibernate linq). Si tel est le cas, vous pouvez également spécifier votre ensemble de constantes dans la requête QueryOver.

public class GetTableQuery 
{ 
    private readonly string _category; 
    private readonly string _language; 

    public GetTableQuery(string category, string language) 
    { 
     _category = category; 
     _language = language; 
    } 

    public IEnumerable<Table1> Execute(ISession session) 
    { 
     var returnList = session.QueryOver<Table1>() 
      .Inner.JoinQueryOver(t1 => t1.Table2) 
      .Where(t2 => t2.Category == _category && t2.Language == _language) 
      .List(); 

     return returnList; 
    } 
} 

Je pense que la méthode AppliquerFiltre montré par Russ ne fait la récupération de modèle beaucoup plus simple, et son très bon pour la réutilisabilité du code (si vous avez d'autres tables avec des catégories et langues), mais étant donné que votre référence de table est une référence nullable, vous devez utiliser une requête quand même. Peut-être une combinaison de QueryOver avec le filtre serait le meilleur (en supposant que vous pouvez obtenir la dernière version de Fluent NHibernate)

1

Vous pouvez jeter un oeil dans Formula(string formula) où vous pourriez fournir SQL pur. Si c'est une bonne idée de filtrer les données sur le niveau de cartographie est une autre question à mon humble avis ... À titre d'exemple, regardez here.

+0

Le problème est que je ne peux pas se permettre d'avoir des sous-requêtes, et la formule ne permet pas de faire référence à l'entité jointe . –

+0

Pourquoi ne pas utiliser HQL ou ICriteria? – sl3dg3

2

Il semble que vous puissiez utiliser des filtres pour cela.

D'abord, vous devez définir les types de filtres

public class SpecificCategoryFilter : FilterDefinition 
{ 
    public SpecificCategoryFilter() 
    { 
     WithName("SpecificCategory").WithCondition("Category = 'A constant expression'"); 
    } 
} 

public class SpecificLanguageFilter : FilterDefinition 
{ 
    public SpecificLanguageFilter() 
    { 
     WithName("SpecificLanguage").WithCondition("Language = 'A constant expression'"); 
    } 
} 

ÉDITÉE: Selon les commentaires, il n'y a pas .ApplyFilter<TFilter>() sur References(), ont donc mis à jour avec ce que je crois est la façon de le faire avec des filtres

les filtres doivent être appliqués dans les applications couramment

public class Table2Map : ClassMap<Table2> 
{ 
    public Table2Map() 
    { 
     // Other mappings here... 

     ApplyFilter<SpecificCategoryFilter>(); 
     ApplyFilter<SpecificLanguageFilter>(); 
    } 
} 

Enfin, lorsque vous ouvrez une session, vous devez activer les filtres

using (var session = sessionFactory.OpenSession()) 
{ 
    session.EnableFilter("SpecificCategory"); 
    session.EnableFilter("SpecificLanguage"); 
} 

Si vous utilisez une implémentation de ICurrentSessionContext et les filtres doivent toujours appliquer alors vous pouvez activer les filtres de la session de retour de l'appel à ICurrentSessionContext.CurrentSession().

Maintenant, lors de l'interrogation Table1, afin de les filtres activer pour Table2, vous devez indiquer NHibernate à se joindre à la Table2 référencé; vous pouvez le faire en utilisant

  1. Fetch(t => t.Table2).Eager
  2. JoinQueryOver(t => t.Table2) (et similaires stratégies de jointure)

Sans indiquer à NHibernate pour faire la jointure, la référence sera paresseusement-chargé par défaut et donc les filtres ne sera pas appliqué dans la requête. L'inconvénient est que Table2 sera recherché, mais je ne connais pas de moyen d'avoir les filtres appliqués autrement. La requête suivante

session.QueryOver<Table1>().Inner.JoinQueryOver(t => t.Table2).List(); 

résultats dans SQL similaire à

SELECT 
    this_.Id as Id0_1_, 
    this_.Table2Id as Table3_0_1_, 
    table2_.Id as Id1_0_, 
    table2_.Category as Category1_0_, 
    table2_.Language as Language1_0_ 
FROM 
    Table1 this_ 
inner join 
    Table2 table2_ 
     on this_.Table2Id=table2_.Id 
WHERE 
    table2_.Category = 'A constant expression' 
    and table2_.Language = 'A constant expression' 

qui est semblable à SQL que vous avez dans votre question.

+0

Supposons que votre version de FNH soit plus récente que la mienne, car je n'ai pas de méthode .ApplyFilter() sur les références. –

+0

Vous avez raison, il n'y a pas - aurait dû l'essayer dans l'IDE :) Ont mis à jour maintenant avec ce que je pense est la meilleure solution en utilisant des filtres. –