Question

J'essaie d'interroger un IList < string > propriété sur l’une de mes classes de domaine avec NHibernate. Voici un exemple simple à démontrer:

public class Demo
{
    public Demo()
    {
        this.Tags = new List<string>();
    }
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<string> Tags { get; set; }
}

Mappé comme ceci:

<class name="Demo">
<id name="Id" />
<property name="Name" />
<bag name="Tags">
  <key column="DemoId"/>
  <element column="Tag" type="String" />
</bag>

Et je suis capable de sauvegarder et de récupérer très bien. Maintenant, pour rechercher les occurrences de ma classe de domaine où la propriété Tags contient une valeur spécifiée:

var demos = this.session.CreateCriteria<Demo>()
            .CreateAlias("Tags", "t")
            .Add(Restrictions.Eq("t", "a"))
            .List<Demo>();

Résultats de l'erreur: la collecte n'était pas une association: Demo.Tags

var demos = (from d in this.session.Linq<Demo>()
                     where d.Tags.Contains("a")
                     select d).ToList();

Résultats de l'erreur: la référence d'objet n'est pas définie sur une instance d'objet.

var demos = this.session.CreateQuery("from Demo d where :t in elements(d.Tags)")
            .SetParameter("t", "a")
            .List<Demo>();

Fonctionne bien, mais comme ma vraie classe de domaine a beaucoup de propriétés et que je construis une requête dynamique compliquée, faire une mauvaise manipulation de chaîne n'est pas mon premier choix. Je préférerais beaucoup utiliser ICriteria ou Linq. J'ai une interface utilisateur où de nombreux critères de recherche possibles peuvent être entrés. Le code qui construit actuellement les ICriteria est composé de dizaines de lignes. Je détesterais vraiment transformer cela en manipulation de chaînes HQL.

Était-ce utile?

La solution

En raison des limitations de l'API Criteria, j'ai donc décidé d'adapter mes classes de domaine.

J'ai créé une classe d'entité pour la balise. Je ne pouvais même pas le créer comme un objet de valeur. Il devait avoir son propre identifiant.

Je me sens sale maintenant. Mais pouvoir construire une requête dynamique sans recourir à la manipulation de chaîne était plus important pour moi que de rester fidèle au domaine.

Autres conseils

Comme indiqué ici:

17.1.4.1. Alias ??et références de propriété

nous pouvons utiliser:

...
A collection key             {[aliasname].key}      ORGID as {coll.key}
The id of an collection      {[aliasname].id}       EMPID as {coll.id}
The element of an collection {[aliasname].element}  XID as {coll.element}
...

il y a un petit bogue dans doc ... au lieu de ".element" , nous devons utiliser ".elements"

var demos = this.session.CreateCriteria<Demo>()
        .CreateAlias("Tags", "t")

        // instead of this
        // .Add(Restrictions.Eq("t", "a"))

        // we can use the .elements keyword
        .Add(Restrictions.Eq("t.elements", "a"))

        .List<Demo>();

Vous devez utiliser des sous-critères et non des alias. Cela devrait fonctionner:

var demos = this.session.CreateCriteria<Demo>()
            .CreateCriteria("Tags")
            .Add(Restrictions.Eq("Tag", "a"))
            .List<Demo>();

HQL:

from Demo d where :val in elements(d.Tags)

Le passage d'une classe à une chaîne est un compromis. Utiliser HQL au lieu de critères est un autre. Il existe cependant un troisième compromis ... utilisez du SQL personnalisé. Essayez ceci.

var demos = Session.CreateCriteria<Demo>()
    .Add(Expression.Sql(
        "EXISTS (SELECT 1 FROM [Tags] custom_sql_t WHERE custom_sql_t.[DemoId] = {alias}.[Id] AND custom_sql_t.[Tag] = ?)",
        "a",
        NHibernateUtil.String))
    .List<Demo>();

Cela a pour résultat que le code SQL suivant est généré par NHibernate 2.1.2.4000 ...

exec sp_executesql N'SELECT this_.Id as Id2_0_, this_.Version as Version2_0_, this_.Name as Name2_0_ FROM Demo this_ WHERE EXISTS (SELECT 1 FROM [Tags] custom_sql_t WHERE custom_sql_t.[DemoId] = this_.[Id] AND custom_sql_t.[Tag] = @p0)',N'@p0 nvarchar(1)',@p0=N'a'

Voir ce message pour un autre exemple ...

NHibernate - Interrogation à partir d'une collection de types de valeur (non-entité) à résoudre Sélectionnez N + 1

Cela est possible en créant un critère distinct:

ICriteria demoCriteria = session.CreateCriteria<Demo>();
...
demoCriteria.Add(Restrictions...);
...
ICriteria tagCriteria = demoCriteria.CreateCriteria("Tags");
tagCriteria.Add(Restrictions.In("elements", new {"Tag1", "Tag2", ...}));

return demoCriteria.List<Demo>();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top