C# Nhibernate Group By和别名为Bean

C# Nhibernate Group By和别名为Bean,c#,nhibernate,group-by,queryover,C#,Nhibernate,Group By,Queryover,我一直在努力把一个老问题翻译成Nhibernate。 我们正在将一个旧项目从Nhibernate 2升级到最新版本。 我使用QueryOver语法,因为由于查询的复杂性(同事的建议),Linq不是一个选项 我想查询DB(Oracle)以获得一些必须分组的结果。 因此,我需要一个分组的DTO集合。我还注意到,nhibernate在转换为具有复杂属性的DTO(嵌套DTO)时遇到困难 为了解决这个问题,我找到了一个主题。这很好,但我不是魔术弦的粉丝 我将添加一些代码片段,说明我的monster查询目前

我一直在努力把一个老问题翻译成Nhibernate。 我们正在将一个旧项目从Nhibernate 2升级到最新版本。 我使用QueryOver语法,因为由于查询的复杂性(同事的建议),Linq不是一个选项

我想查询DB(Oracle)以获得一些必须分组的结果。 因此,我需要一个分组的DTO集合。我还注意到,nhibernate在转换为具有复杂属性的DTO(嵌套DTO)时遇到困难 为了解决这个问题,我找到了一个主题。这很好,但我不是魔术弦的粉丝

我将添加一些代码片段,说明我的monster查询目前的情况。 问题是,我似乎不知道如何在不破坏其他所有内容的情况下添加组。因此,我希望对一个属性进行分组,但结果中仍然包含DTO。比如:

ILookup<int,IEnumerable<NieuwePrintopdrachtenInfo>>
这只是开始。下面是过滤结果的部分(需要时)

然后我得到了选择我需要的东西的部件,并将其转换为DTO(nieuwepintopdrachteninfo)

是的,我知道这是一团糟。现在你已经走了这么远,你会很高兴知道我们就快到了。这是我用来返回结果的代码(它是通用的,使用我找到的DeepTransform)

受保护的IEnumerable GetDeepTransformedPagedList(IQueryOver查询),其中TR:class
{
PagingSettings.Count=query.Clone().Select(Projections.CountDistinct(PagingSettings.PropertyNameToCountOn)).FutureValue().Value;
query=query.TransformUsing(new DeepTransformer());
如果(PagingSettings.Enabled)
{
var pagedQuery=query.Skip(GetPagingStartRowIndex()).Take(PagingSettings.PageSize);
返回pagedQuery.List();
}
返回query.List();
}

编辑

在Radim Köhler发表了一篇有用的帖子之后,我发现一个小组的人不会帮我解决问题。这就是为什么我要解释真正的问题。 在代码中,前面的查询是构建的,并使用Skip&Take进行扩展,用于分页。在我的情况下,执行查询时会得到50个结果。 这50个结果包含重复项,需要按UitgaandeBriefId进行分组。 这就是为什么最初的开发人员编写了这段代码,一旦结果从数据库返回,就会执行这段代码

ILookup<int, IEnumerable<NieuwePrintopdrachtenInfo>> groupedbrieven =
            (from tbInfo in brieven
             group tbInfo by tbInfo.UitgaandeBriefId into g
             let UitgaandeBriefId = g.Key
             let Group = g as IEnumerable<NieuwePrintopdrachtenInfo>
             select new { UitgaandeBriefId, Group })
             .ToLookup(result => result.UitgaandeBriefId, result => result.Group);
ILookup GroupedBrien=
(来自brieven的tbInfo)
按tbInfo.UITGANDEBREATEID将tbInfo分组到g中
设UtgaandeBriefId=g.键
设群=g为IEnumerable
选择新的{UITGANDEBREATEID,组})
.ToLookup(result=>result.uitgaindebriefid,result=>result.Group);
这段代码仍然有效,但只得到32个结果。这使得我的页面永远不会包含50个结果。最初的开发人员使用服务器端分页,而不是在数据库上进行分页,因此他从未遇到过这个问题(从性能角度看,这是一个巨大的问题)。这就是为什么我对它进行了重构,这样它的执行速度会快很多,但这样做的结果并不是非常好地得到50个结果。
我想我需要添加一个独特的,但我不知道如何在NHibernate中使用它,因为我习惯于使用EntityFramework。

一般来说,如果我们想将投影更改为使用GROUP BY,我们必须将所有“选择”部分更改为GROUP BY的一部分或SUM,MIN

我们可以用这种语法来做

// firstly 
// the original part from the question above
baseQuery.SelectList(list => list
    ...
    .Select(() => joinedBriefBestemmeling.BinnenLand)
       .WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingBinnenLand)
    .Select(() => joinedVerbruiksAdres.Land)
       .WithAlias(() => nieuwePrintopdrachtInfo.LandVerbuiksadres)
    .Select(Projections.Property(() => joinedContactpersoon.ContactpersoonId)
       .As("BestemmelingContactPersoon.ContactPersoonId"))
    .Select(Projections.Property(() => joinedContactpersoonType.Omschrijving)
       .As("BestemmelingContactPersoon.TypeContactPersoon"))
    ...



// changed, to use GROUP BY
baseQuery.SelectList(list => list
    ...
    .SelectGroup(() => joinedBriefBestemmeling.BinnenLand)
       .WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingBinnenLand)
    .SelectGroup(() => joinedVerbruiksAdres.Land)
       .WithAlias(() => nieuwePrintopdrachtInfo.LandVerbuiksadres)
    .Select
       (Projections.Alias
         (Projections.GroupProperty
           (Projections.Property(() => joinedContactpersoon.ContactpersoonId))
         , "BestemmelingContactPersoon.ContactPersoonId"))
    .Select
       (Projections.Alias
         (Projections.GroupProperty
           (Projections.Property(() => joinedContactpersoonType.Omschrijving))
         , "BestemmelingContactPersoon.TypeContactPersoon"))
     ...
因此,现在我们使用GROUP BY(而不仅仅是SELECT)替换原始代码。但我们可以做得更多,我们可以引入这些(只是一个快速版本)扩展方法(只是一个轻量级的版本,真的-但工作正常)


注意IsNull()也是扩展名

谢谢您的回答。这真的帮了我很多忙。但似乎对每件事进行分组并不能给我想要的结果。使用SelectGroup有效,但似乎无法解决我的问题。我会更新我的问题来解释它。我也试过你的扩展方法。它看起来比我用的好多了。问题是我现在得到了NullReferenceExceptions。像往常一样,错误集中在执行查询的部分,因此找到真正的问题是一件痛苦的事情。。。我开始调试ParseProperty方法,大多数时候“body”实际上是空的。我是不是漏掉了什么?K看起来我已经修好了。我认为你的版本被删减得太多了。我添加了一些额外的内容来检查“节点类型”,当它是“ExpressionType.Convert”时,我将它用作我的主体“((UnaryExpression)expression.body)。操作数作为成员表达式”现在就像一个符咒。现在我只需要返回正确的结果对不起,没有完成扩展。。。我只是想告诉你如何封装如此复杂的投影树。。。变成一个小的扩展(避免使用神奇的字符串)。我在本地测试了一个小示例,所有这些都对我有用。整体而言,团队是必须的(试着自己创建SQL语句,不要将S SELECT中的每个语句都放入GROUP by中-它会失败,除非您使用MIN、MAX…是的,我认为GROUP by在我的情况下没有用。我想我需要做一个Distinct,以确保不会因为加入而得到重复的语句。是否可以在UITGANDEBRI上只做一个DistinctefId,但仍然获得所有其他信息?我现在将编辑我的问题,以便更好地解释情况。
NieuwePrintopdrachtenInfo nieuwePrintopdrachtInfo = null;
baseQuery.SelectList(list => list
    .Select(() => uitgaandebrief.UitgaandebriefId).WithAlias(() => nieuwePrintopdrachtInfo.UitgaandeBriefId)
    .Select(() => uitgaandebrief.DatumInplanning).WithAlias(() => nieuwePrintopdrachtInfo.InplanningsDatum)
    .Select(() => uitgaandebrief.ErrorReden).WithAlias(() => nieuwePrintopdrachtInfo.Probleem)
    .Select(() => uitgaandebrief.ErrorNr).WithAlias(() => nieuwePrintopdrachtInfo.ErrorNummer)
    .Select(() => uitgaandebrief.DatumCreatie).WithAlias(() => nieuwePrintopdrachtInfo.CreatieDatumBrief)
    .Select(() => uitgaandebrief.DatumUpdate).WithAlias(() => nieuwePrintopdrachtInfo.DatumLaatsteWijzigingBrief)
    .Select(() => uitgaandebrief.UserCreatie).WithAlias(() => nieuwePrintopdrachtInfo.BrieUserCreatie)
    .Select(() => uitgaandebrief.UserUpdate).WithAlias(() => nieuwePrintopdrachtInfo.BriefUserUpdate)
    .Select(() => uitgaandebrief.DatumAnnulatieElektriciteit).WithAlias(() => nieuwePrintopdrachtInfo.DatumElektriciteitGeannuleerd)
    .Select(() => uitgaandebrief.DatumAnnulatieGas).WithAlias(() => nieuwePrintopdrachtInfo.DatumGasGeannuleerd)
    .Select(() => joinedDossier.DossierId).WithAlias(() => nieuwePrintopdrachtInfo.DossierId)
    .Select(() => joinedDossier.DossierNr).WithAlias(() => nieuwePrintopdrachtInfo.DossierNr)
    .Select(() => joinedEnergieType.Omschrijving).WithAlias(() => nieuwePrintopdrachtInfo.EnergieTypeBrief)
    .Select(() => joinedBriefType.Omschrijving).WithAlias(() => nieuwePrintopdrachtInfo.TypeBrief)
    .Select(() => joinedVerzendModus.Omschrijving).WithAlias(() => nieuwePrintopdrachtInfo.VerzendModus)
    .Select(() => joinedVerzendModus.Omschrijving).WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingVerzendModus)
    .Select(() => joinedBriefBestemmeling.BriefBestemmelingenId).WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingId)
    .Select(() => joinedBestemmelingType.Omschrijving).WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingContactpersoonType)
    .Select(() => joinedBriefBestemmeling.BestemmelingElektriciteit).WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingElek)
    .Select(() => joinedBriefBestemmeling.BestemmelingGas).WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingGas)
    .Select(() => joinedBriefBestemmeling.BinnenLand).WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingBinnenLand)
    .Select(() => joinedVerbruiksAdres.Land).WithAlias(() => nieuwePrintopdrachtInfo.LandVerbuiksadres)
    .Select(Projections.Property(() => joinedContactpersoon.ContactpersoonId).As("BestemmelingContactPersoon.ContactPersoonId"))
    .Select(Projections.Property(() => joinedContactpersoonType.Omschrijving).As("BestemmelingContactPersoon.TypeContactPersoon"))
    .Select(Projections.Property(() => joinedContactpersoon.VoorNaam).As("BestemmelingContactPersoon.VoorNaam"))
    .Select(Projections.Property(() => joinedContactpersoon.Naam).As("BestemmelingContactPersoon.Naam"))
    .Select(Projections.Property(() => joinedContactpersoon.Straat).As("BestemmelingContactPersoon.Straat"))
    .Select(Projections.Property(() => joinedContactpersoon.HuisNr).As("BestemmelingContactPersoon.HuisNummer"))
    .Select(Projections.Property(() => joinedContactpersoon.BusNr).As("BestemmelingContactPersoon.BusNummer"))
    .Select(Projections.Property(() => joinedContactpersoon.Gemeente).As("BestemmelingContactPersoon.Gemeente"))
    .Select(Projections.Property(() => joinedContactpersoon.PostCode).As("BestemmelingContactPersoon.PostCode"))
    .Select(Projections.Property(() => joinedContactpersoon.Appartement).As("BestemmelingContactPersoon.Appartement"))
    .Select(Projections.Property(() => joinedContactpersoon.Verdieping).As("BestemmelingContactPersoon.Verdieping"))
    .Select(Projections.Property(() => joinedContactpersoon.Telefoon1).As("BestemmelingContactPersoon.Telefoon1"))
    .Select(Projections.Property(() => joinedContactpersoon.Telefoon2).As("BestemmelingContactPersoon.Telefoon2"))
    .Select(Projections.Property(() => joinedContactpersoon.FAXNr).As("BestemmelingContactPersoon.Fax"))
    .Select(Projections.Property(() => joinedContactpersoon.Email).As("BestemmelingContactPersoon.Email"))
    .Select(Projections.Property(() => joinedContactpersoon.DatumCreatie).As("BestemmelingContactPersoon.DatumCreatie"))
    .Select(Projections.Property(() => joinedContactpersoon.UserCreatie).As("BestemmelingContactPersoon.UserCreatie"))
    .Select(Projections.Property(() => joinedContactpersoon.DatumUpdate).As("BestemmelingContactPersoon.DatumUpdate"))
    .Select(Projections.Property(() => joinedContactpersoon.UserUpdate).As("BestemmelingContactPersoon.UserUpdate"))
    .Select(Projections.Property(() => joinedContactpersoon.AdresBijTeWerken).As("BestemmelingContactPersoon.IsAdresBijTeWerken"))
    .Select(Projections.Property(() => joinedContactpersoon.Titel).As("BestemmelingContactPersoon.Titel"))
    .Select(Projections.Property(() => joinedContactpersoon.NietBesteldeBrief).As("BestemmelingContactPersoon.NietBesteldeBrief"))
    .Select(Projections.Property(() => joinedContactpersoon.Land).As("BestemmelingContactPersoon.Land"))
    .Select(Projections.Property(() => joinedContactpersoon.ContactpersoonAlsAanbrengerGebruikt).As("BestemmelingContactPersoon.ContactPersoonIdAlsAanbrenger"))
    .Select(Projections.Property(() => joinedContactpersoon.ContactpersoonIsBetrokken).As("BestemmelingContactPersoon.ContactPersoonIsBetrokken"))
    .Select(Projections.Property(() => joinedContactpersoon.NietAfgehaaldeBrief).As("BestemmelingContactPersoon.NietAfgehaaldeBrief"))
    .Select(Projections.Property(() => joinedContactpersoonTaal.Omschrijving).As("BestemmelingContactPersoon.Taal"))
    .Select(Projections.Property(() => joinedProfielGroep.Omschrijving).As("BestemmelingContactPersoon.IngegevenDoor"))
    .Select(Projections.Property(() => joinedEan.Energietype).As("BestemmelingContactPersoon.EnergieType"))
    .Select(Projections.Property(() => joinedVerbruiksVerantw.ToewijzigingVerbruiksVerantwoordelijkeId).As("BestemmelingContactPersoon.VerbruiksVerantwoordelijkeId")));
protected IEnumerable<TR> GetDeepTransformedPagedList<T, TR>(IQueryOver<T, T> query) where TR : class
{
    PagingSettings.Count = query.Clone().Select(Projections.CountDistinct(PagingSettings.PropertyNameToCountOn)).FutureValue<int>().Value;
    query = query.TransformUsing(new DeepTransformer<TR>());

    if (PagingSettings.Enabled)
    {
        var pagedQuery = query.Skip(GetPagingStartRowIndex()).Take(PagingSettings.PageSize);
        return pagedQuery.List<TR>();
    }

    return query.List<TR>();
}
ILookup<int, IEnumerable<NieuwePrintopdrachtenInfo>> groupedbrieven =
            (from tbInfo in brieven
             group tbInfo by tbInfo.UitgaandeBriefId into g
             let UitgaandeBriefId = g.Key
             let Group = g as IEnumerable<NieuwePrintopdrachtenInfo>
             select new { UitgaandeBriefId, Group })
             .ToLookup(result => result.UitgaandeBriefId, result => result.Group);
// firstly 
// the original part from the question above
baseQuery.SelectList(list => list
    ...
    .Select(() => joinedBriefBestemmeling.BinnenLand)
       .WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingBinnenLand)
    .Select(() => joinedVerbruiksAdres.Land)
       .WithAlias(() => nieuwePrintopdrachtInfo.LandVerbuiksadres)
    .Select(Projections.Property(() => joinedContactpersoon.ContactpersoonId)
       .As("BestemmelingContactPersoon.ContactPersoonId"))
    .Select(Projections.Property(() => joinedContactpersoonType.Omschrijving)
       .As("BestemmelingContactPersoon.TypeContactPersoon"))
    ...



// changed, to use GROUP BY
baseQuery.SelectList(list => list
    ...
    .SelectGroup(() => joinedBriefBestemmeling.BinnenLand)
       .WithAlias(() => nieuwePrintopdrachtInfo.BestemmelingBinnenLand)
    .SelectGroup(() => joinedVerbruiksAdres.Land)
       .WithAlias(() => nieuwePrintopdrachtInfo.LandVerbuiksadres)
    .Select
       (Projections.Alias
         (Projections.GroupProperty
           (Projections.Property(() => joinedContactpersoon.ContactpersoonId))
         , "BestemmelingContactPersoon.ContactPersoonId"))
    .Select
       (Projections.Alias
         (Projections.GroupProperty
           (Projections.Property(() => joinedContactpersoonType.Omschrijving))
         , "BestemmelingContactPersoon.TypeContactPersoon"))
     ...
public static class Extensions
{
    public static NHibernate.Criterion.Lambda.QueryOverProjectionBuilder<T> GroupByProperty<T>(
        this NHibernate.Criterion.Lambda.QueryOverProjectionBuilder<T> builder, 
        System.Linq.Expressions.Expression<Func<object>> propertyExpression,
        System.Linq.Expressions.Expression<Func<object>> aliasExpression)
    {
        var alias = aliasExpression.ParseProperty();

        var propertyProjection = Projections.Property(propertyExpression);
        var groupProjection = Projections.GroupProperty(propertyProjection);
        var withAliasProjection = Projections.Alias(groupProjection, alias);

        builder.Select(withAliasProjection);
        return builder;
    }

    public static string ParseProperty<TFunc>(this System.Linq.Expressions.Expression<TFunc> expression)
    {
        var body = expression.Body as System.Linq.Expressions.MemberExpression;
        if (body.IsNull())
        {
            return null;
        }

        string propertyName = body.Member.Name;

        ParseParentProperty(body.Expression as System.Linq.Expressions.MemberExpression, ref propertyName);

        // change the   alias.ReferenceName.PropertyName
        // to just            ReferenceName.PropertyName
        var justAPropertyChain = propertyName.Substring(propertyName.IndexOf('.') + 1);
        return justAPropertyChain;
    }

    static void ParseParentProperty(System.Linq.Expressions.MemberExpression expression, ref string propertyName)
    {
        if (expression.IsNull())
        {
            return;
        }
        // Parent.PropertyName
        propertyName = expression.Member.Name + "." + propertyName;

        ParseParentProperty(expression.Expression as System.Linq.Expressions.MemberExpression, ref propertyName);
    }
}
baseQuery.SelectList(list => list
    ...
    .GroupByProperty(() => joinedBriefBestemmeling.BinnenLand)
       ,() => nieuwePrintopdrachtInfo.BestemmelingBinnenLand)
    .GroupByProperty(() => joinedVerbruiksAdres.Land)
       ,() => nieuwePrintopdrachtInfo.LandVerbuiksadres)
    .GroupByProperty(() => joinedContactpersoon.ContactpersoonId)
       .() => nieuwePrintopdrachtInfo.BestemmelingContactPersoon.ContactPersoonId)
    .GroupByProperty(() => joinedContactpersoonType.Omschrijving)
       .() => nieuwePrintopdrachtInfo.BestemmelingContactPersoon.TypeContactPersoon)
    ...