Frage

Ich versuche, Abfrage gegen eine IList<string> Eigentum an einer meiner domain-Klassen mit NHibernate.Hier ist ein einfaches Beispiel, um zu demonstrieren:

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; }
}

Zugeordnet wie diese:

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

Und ich bin in der Lage, speichern und abrufen nur feine.Jetzt die Abfrage für Instanzen von meiner domain-Klasse, wo die Tags-Eigenschaft enthält einen angegebenen Wert:

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

Der Fehler ergibt:die Sammlung war nicht eine Assoziation:Demo.Tags

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

Der Fehler ergibt:Objct Referenz nicht auf eine Instanz eines Objekts.

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

Funktioniert gut, aber wie meine echte domain-Klasse hat viele Eigenschaften, und ich bin Gebäude eine komplizierte dynamische Abfrage, tun hässlich string-manipulation ist nicht meine erste Wahl.Ich würde viel lieber ICriteria oder Linq.Ich habe eine Benutzeroberfläche, wo viele verschiedene Suchkriterien eingegeben werden können.Der code, der baut die ICriteria jetzt Dutzende von Zeilen lang.Ich würde es wirklich hassen, um zu drehen, die in HQL string-manipulation.

War es hilfreich?

Lösung

So aufgrund von Einschränkungen des Kriterien-API, entschied ich meine Domain-Klassen zu biegen passen.

Ich habe eine Entität-Klasse für den Tag. Ich konnte nicht einmal sie als Wertobjekt erstellen. Es musste eine eigene ID haben.

Ich fühle mich jetzt schmutzig. Aber in der Lage, eine dynamische Abfrage zu konstruieren, wurde ohne Rückgriff auf String-Manipulation wichtiger für mich als treu bleibt die Domäne.

Andere Tipps

Wie hier dokumentiert:

17.1.4.1.Alias-und property-Referenzen

wir Sie verwenden können:

...
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}
...

es ist eine kleine Fehler in doc...statt ".element" wir haben die Verwendung von ".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>();

Sie müssen verwenden SubCriterias nicht Pseudonyms gestattet.Sollte dies funktionieren:

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)

Umschalten auf eine Klasse über einen String ist ein Kompromiss. Mit HQL statt ICriteria ist eine andere. Es gibt einen dritten Kompromiss jedoch ... benutzerdefinierte SQL verwenden. Versuchen Sie, diese aus.

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>();

Dies führt in der follwing SQL von NHibernate generiert wird 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'

Sehen Sie diesen Beitrag für ein anderes Beispiel ...

NHibernate - Querying aus einer Sammlung von Werttypen (nicht-Entity) Wählen N + 1

lösen

Dies ist möglich, indem ein separaten Kriterien erstellen:

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>();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top