Precisa de ajuda convertendo SQL com critérios API
-
08-07-2019 - |
Pergunta
Eu tenho um aplicativo NHibernate que atualmente faz uso de uma função definida pelo usuário SQL Server. Eu gostaria de evitar ter que chamar esta função e, em vez expressar sua lógica usando o NH critérios API. Infelizmente, eu estou tendo dificuldade em aplicar os exemplos de critérios na documentação NH para o meu caso particular. Então, eu estou voltando para este site para obter ajuda.
Aqui é a função. Leva um único argumento de cadeia e retorna uma tabela. A função executa 3 junções entre os mesmos 2 mesas, mas com diferentes critérios de união, e depois funde-se o resultado.
Alguma dica seria apreciada. Agradecemos antecipadamente!
Editar:. Um comentário nos estados resposta aceita que a conversão não é possível, que é a correta ??em> resposta ??p>
Aqui está o mapeamento para as 3 classes envolvidas: 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
);
<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>
Solução
isso pode fazer o trabalho (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"));
nota, porém, que esta não gera ANSI sintaxe participar, mas coloca as restrições em uma cláusula WHERE. Eu realmente não acho que isso é um problema, você está fazendo uma junção interna e não uma associação externa.
Também eu não me lembro agora a notação parâmetro adequado na Expression.Sql
.
Eu defini-lo como :LangId
embora também possa ser @LangId
sidenote: como você pode ver, embora este é um critério de consulta é apenas um monte de SQL-indicações divididas, de modo que se encaixam no critério API; você tem certeza que é isso que você precisa?