Hai bisogno di aiuto per convertire SQL in criteri API
-
08-07-2019 - |
Domanda
Ho un'applicazione NHibernate che attualmente utilizza una funzione definita dall'utente di SQL Server. Vorrei evitare di dover chiamare questa funzione e invece esprimere la sua logica utilizzando l'API dei criteri NH. Sfortunatamente, ho difficoltà ad applicare gli esempi di criteri nella documentazione NH al mio caso particolare. Quindi mi rivolgo a questo sito per aiuto.
Ecco la funzione. Prende un singolo argomento stringa e restituisce una tabella. La funzione esegue 3 join tra le stesse 2 tabelle ma con criteri di join diversi, quindi unisce il risultato.
Eventuali suggerimenti sarebbero apprezzati. Grazie in anticipo!
Modifica: si rivolge a NH 2.1
Modifica: un commento nella risposta accettata afferma che la conversione non è possibile, che è la risposta corretta.
CREATE FUNCTION dbo.GetRevisionText
(
@LangId NVARCHAR(16)
)
RETURNS TABLE
AS
RETURN
(
SELECT r.RevisionId,
COALESCE(lp1.Title, lp2.Title, lp3.Title) Title,
COALESCE(lp1.Description, lp2.Description, lp3.Description) Description
FROM Revision r
LEFT JOIN LocalizedProperty lp1
ON lp1.RevisionId = r.RevisionId
AND lp1.LanguageId = @LangId
LEFT JOIN LocalizedProperty lp2
ON lp2.RevisionId = r.RevisionId
AND lp2.LanguageId = LEFT(@LangId, 2)
LEFT JOIN LocalizedProperty lp3
ON lp3.RevisionId = r.RevisionId
AND lp3.LanguageId = r.DefaultPropertiesLanguage
);
Ecco la mappatura per le 3 classi coinvolte:
<class name="Revision">
<id name="RevisionId" type="Guid">
<generator class="assigned"/>
</id>
<set name="LocalizedProperties" inverse="true" lazy="true" cascade="all-delete-orphan">
<key column="RevisionId"/>
<one-to-many class="LocalizedProperty"/>
</set>
<many-to-one name="DefaultPropertiesLanguage" class="Language" not-null="true"/>
</class>
<class name="Language">
<id name="LanguageId" type="String" length="16">
<generator class="assigned"/>
</id>
<property name="Lcid" type="Int32" unique="true" not-null="true"/>
</class>
<class name="LocalizedProperty" mutable="false">
<composite-id>
<key-many-to-one name="Revision" class="Revision" column="RevisionId"/>
<key-many-to-one name="Language" class="Language" column="LanguageId"/>
</composite-id>
<property name="Title" type="String" length="200" not-null="true"/>
<property name="Description" type="String" length="1500" not-null="false"/>
</class>
Soluzione
questo potrebbe fare il lavoro (NH 1.2):
var crit = nhSes.CreateCriteria(typeof(Revision), "r")
.SetProjection(
Projections.SqlProjection(@"r.RevisionId as rid,
COALESCE(lp1.Title, lp2.Title, lp3.Title) as Title,
COALESCE(lp1.Description, lp2.Description, lp3.Description) as Description", new[] {"rid", "Title", "Description"}, new[] {NHibernateUtil.Guid, NHibernateUtil.String,NHibernateUtil.String})
);
crit.CreateCriteria("LocalizedProperty", "lp1", JoinType.InnerJoin);
crit.CreateCriteria("LocalizedProperty", "lp2", JoinType.InnerJoin);
crit.CreateCriteria("LocalizedProperty", "lp3", JoinType.InnerJoin);
crit.Add(Expression.Eq("lp1.LanguageId", langId));
crit.Add(Expression.Sql("lp2.LanguageId = LEFT(:LangId, 2)", langId, NHibernateUtil.String));
crit.Add(Expression.EqProperty("lp3.LanguageId", "r.DefaultPropertiesLanguage"));
notare tuttavia che ciò non genera un join di sintassi ANSI ma inserisce i vincoli in una clausola WHERE. Non penso davvero che sia un problema, stai facendo un join interno e non un join esterno.
Inoltre non ricordo ora la corretta notazione dei parametri su Expression.Sql
.
L'ho definito come : LangId
sebbene possa anche essere @LangId
sidenote: come puoi vedere, sebbene si tratti di una query di criteri, è solo una serie di istruzioni sql suddivise in modo da adattarsi all'API dei criteri; sei sicuro che questo è quello che ti serve?