2009-11-29 5 views
0

J'ai une application NHibernate qui utilise actuellement une fonction SQL Server définie par l'utilisateur. Je voudrais éviter d'avoir à appeler cette fonction, et à la place exprimer sa logique en utilisant l'API des critères NH. Malheureusement, j'ai de la difficulté à appliquer les exemples de critères dans la documentation de NH à mon cas particulier. Je me tourne donc vers ce site pour obtenir de l'aide.Besoin d'aide pour convertir SQL en critères API

Voici la fonction. Il prend un seul argument de chaîne et renvoie une table. La fonction effectue 3 jointures entre les deux mêmes tables mais avec des critères de jointure différents, puis fusionne le résultat.

Tous les conseils seraient appréciés. Merci d'avance!

Edit: Ce vise NH 2.1

Edit: un commentaire dans la réponse acceptée précise que la conversion n'est pas possible, ce qui est le correct réponse.

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

Voici la mise en correspondance pour les 3 classes concernées:

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

Répondre

1

cela pourrait faire le travail (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")); 

noter cependant que cela ne génère pas la syntaxe ANSI join mais place les contraintes dans une clause WHERE. Je ne pense pas vraiment que ce soit un problème, vous faites une jointure interne et non une jointure externe.

Aussi je ne me souviens pas maintenant la notation de paramètre correcte sur Expression.Sql. Je l'ai défini comme :LangId bien qu'il puisse aussi être @LangId

sidenote: comme vous pouvez le voir même si cela est un critère complexée de sa juste un tas d'instructions SQL-split pour ainsi adapter l'API de critères; Es-tu sûr que c'est ce dont tu as besoin?

+0

Merci pour votre aide, ça m'a donné une longueur d'avance. Malheureusement, cela ne marche pas :(NH se plaint de "chemin d'association en double: LocalizedProperty". J'étudie actuellement la cartographie des alias 2 et 3 de LocalizedProperty avec des vues ... –

+0

avez-vous essayé d'utiliser crit.CreateAlias ​​("LocalizedProperty" , "lp1"); il va probablement jeter la même erreur mais vous n'avez rien à perdre – Jaguar

+0

meh il semble qu'il n'est pas pris en charge ... vérifier http://nhjira.koah.net/browse/NH-2016 .. Si vous voulez vraiment porter le code de la base de données vers votre application, une ISQLQuery est le seul moyen – Jaguar