C# NHibernate-将LINQ/Lambda表达式移动到方法中会更改生成的SQL-为什么?

C# NHibernate-将LINQ/Lambda表达式移动到方法中会更改生成的SQL-为什么?,c#,linq,lambda,nhibernate,hql,C#,Linq,Lambda,Nhibernate,Hql,我在.NET Framework 4.7.2上使用NHibernate 5.2.0.0,我注意到它生成不同的SQL,这取决于LINQ/lambda表达式是否在方法中。我想把它放在一个方法中(使其可重用,更易于重构),并且仍然能够生成更好的SQL 这是整个语句,相关部分是DocumentType=…。这就是我想在其他100个控制器中使用的部分,我不想复制粘贴到那里 var billingDocumentList = from billingDoc in billingDocuments

我在.NET Framework 4.7.2上使用NHibernate 5.2.0.0,我注意到它生成不同的SQL,这取决于LINQ/lambda表达式是否在方法中。我想把它放在一个方法中(使其可重用,更易于重构),并且仍然能够生成更好的SQL

这是整个语句,相关部分是
DocumentType=…
。这就是我想在其他100个控制器中使用的部分,我不想复制粘贴到那里

var billingDocumentList = from billingDoc in billingDocuments
                          where branchIdPermissions.Contains(billingDoc.Branch.Id)
                          let taxAmount = billingDoc.BillingDocumentPositions.Sum(p => p.Amount * (p.TaxRate / 100M))
                          select new BillingDocumentOverviewViewModel
                                  {
                                      Id = billingDoc.Id,
                                      BillingDocumentNumber = billingDoc.BillingDocumentNumber,
                                      DocumentStatus = billingDoc.DocumentStatus.Description,
                                      BillingDocumentDate = billingDoc.BillingDocumentDate.Date,
                                      Company = billingDoc.Branch.Company.CompanyNumber + "-" + billingDoc.Branch.Company.Description,
                                      DocumentType =billingDoc.DocumentType.Description2.Translations.Where(x => x.Language.ISO2 == Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName || x.Language.ISO2 == "en").Select(n => new { n.Value, fallback = n.Language.ISO2 == "en" ? 1 : 0 }).OrderBy(x => x.fallback).Select(x => x.Value).FirstOrDefault(),
                                      RecipientName1 = billingDoc.RecipientName1,
                                  };
所以我试着把它放到
短语
类中(类型为
Description2
属性)

虽然Nhibernates为内联变量生成(快速)子查询,但在将其移动到方法中时,它会生成额外的独立查询,这是我想要避免的

我的目标是生成与第一个变体相同的SQL,但使其在大型软件产品上可重用,并将逻辑保持在一个地方

我已经尝试过使用方法实现和扩展方法,但没有任何效果

目前,我正试图通过深入挖掘NHibernate来实现我的目标。我正试图编写一个定制的
BaseHqlGeneratorForMethod
实现,并将所有Linq语句放入其中。那对我来说很好。想象一下:

DocumentType = billingDocs.DocumentType.Description2.InCurrentLocale(),
.......
.....

public class InCurrentLocaleGenerator2 : BaseHqlGeneratorForMethod
{
    public InCurrentLocaleGenerator2()
    {
        SupportedMethods = new[]
        {
            ReflectHelper.GetMethodDefinition<Phrase>((x) => x.InCurrentLocale())
        };
    }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
      Expression<Func<Translation, bool>> languageExp = (x) => x.Language.ISO2 == currentLanguage || x.Language.ISO2 == "en";
      
      /// + the other parts of the complete LINQ statement

        return visitor.Visit(languageExp).AsExpression();
..........
......
}
DocumentType=billingDocs.DocumentType.Description2.IncirentLocale(),
.......
.....
公共类InrirentLocaleGenerator2:BaseHqlGeneratorFormMethod
{
公共事件LocaleGenerator2()
{
SupportedMethods=new[]
{
ReflectHelper.GetMethodDefinition((x)=>x.IncirentLocale())
};
}
公共重写HqlTreeNode BuildHql(MethodInfo方法、表达式targetObject、只读集合参数、HqlTreeBuilder treeBuilder、IHqlExpressionVisitor)
{
表达式语言exp=(x)=>x.Language.ISO2==currentLanguage | | x.Language.ISO2==“en”;
///+完整LINQ声明的其他部分
return visitor.Visit(languageExp.AsExpression();
..........
......
}
但我总是会犯不同的错误,因为我对写表达对象和所有与之相关的东西没有很好的经验


有什么方法可以实现我想要的吗?这不是HQL的方法,我会非常高兴并感谢所有其他的想法/方法或指导方针如何用HQL实现这一点。谢谢!

这是因为,
incirentLocale
不是一个表达式,没有任何LINQ提供者可以解析它。 这里最简单的方法是使用可以将表达式注入当前表达式树的方法:

public virtual Expression<Func<IEnumerable<Translation>, string>> InCurrentLocale()
{
    return (translations) => translations.Where(x => x.Language.ISO2 == Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName || x.Language.ISO2 == "en")
             .Select(n => new { n.Value, fallback = n.Language.ISO2 == "en" ? 1 : 0 })
             .OrderBy(x => x.fallback)
             .Select(x => x.Value)
             .FirstOrDefault();
}

评论不适用于长时间的讨论;此对话已结束。
public virtual Expression<Func<IEnumerable<Translation>, string>> InCurrentLocale()
{
    return (translations) => translations.Where(x => x.Language.ISO2 == Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName || x.Language.ISO2 == "en")
             .Select(n => new { n.Value, fallback = n.Language.ISO2 == "en" ? 1 : 0 })
             .OrderBy(x => x.fallback)
             .Select(x => x.Value)
             .FirstOrDefault();
}
var billingDocumentList = from billingDoc in billingDocuments.AsExpandable()
                          where branchIdPermissions.Contains(billingDoc.Branch.Id)
                          let taxAmount = billingDoc.BillingDocumentPositions.Sum(p => p.Amount * (p.TaxRate / 100M))
                          select new BillingDocumentOverviewViewModel
                                  {
                                      Id = billingDoc.Id,
                                      BillingDocumentNumber = billingDoc.BillingDocumentNumber,
                                      DocumentStatus = billingDoc.DocumentStatus.Description,
                                      BillingDocumentDate = billingDoc.BillingDocumentDate.Date,
                                      Company = billingDoc.Branch.Company.CompanyNumber + "-" + billingDoc.Branch.Company.Description,
                                      DocumentType = InCurrentLocale().Invoke(billingDoc.DocumentType.Description2.Translations),
                                      RecipientName1 = billingDoc.RecipientName1,
                                  };