Nhibernate Group By and Alias To Bean

本文关键字:To Bean Alias and Group By Nhibernate | 更新日期: 2023-09-27 18:10:36

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

我想查询数据库(Oracle),以获得一些必须分组的结果。因此,我需要DTO的分组集合。我还注意到,nhibernate在转换为具有复杂属性的DTO(嵌套DTO)时遇到了麻烦。为了解决这个问题,我找到了这个话题。这工作得很好,但我不是魔法字符串的粉丝…

我将添加一些代码片段,说明我的怪物查询此刻的样子。问题是我似乎不知道如何在不破坏其他东西的情况下添加一个组。所以我想在一个属性上分组,但仍然在我的结果中有DTO。比如:

ILookup<int,IEnumerable<NieuwePrintopdrachtenInfo>>

欢迎任何帮助。

抱歉变量和类都是荷兰语-_-

SYNUITGAANDEBRIEF uitgaandebrief = null;
SYNAANVRAAG joinedAanvraag = null;
SYNDOSSIER joinedDossier = null;
SYNVERBRUIKSADRES joinedVerbruiksAdres = null;
SYNEAN joinedEan = null;
SYNCTENERGIETYPE joinedEnergieType = null;
SYNBRIEFBESTEMMELINGEN joinedBriefBestemmeling = null;
SYNCTBRIEFTYPE joinedBriefType = null;
SYNCTBRIEFSTATUS joinedBriefStatus = null;
SYNCONTACTPERSOON joinedContactpersoon = null;
SYNCTCONTACTPERSOONTYPE joinedBestemmelingType = null;
SYNCTVERZENDMODUSTYPE joinedVerzendModus = null;
SYNCTCONTACTPERSOONTYPE joinedContactpersoonType = null;
SYNCTTAAL joinedContactpersoonTaal = null;
SYNTOEWIJZVERBRUIKVERANT joinedVerbruiksVerantw = null;
SYNCTPROFIELGROEP joinedProfielGroep = null;
var baseQuery = SessionHandler.CurrentSession.QueryOver(() => uitgaandebrief)
    .JoinAlias(() => uitgaandebrief.AANVRAAGCollection, () => joinedAanvraag)
    .JoinAlias(() => joinedAanvraag.DOSSIER, () => joinedDossier)
    .JoinAlias(() => joinedDossier.VERBRUIKSADRES, () => joinedVerbruiksAdres)
    .JoinAlias(() => joinedAanvraag.EAN, () => joinedEan)
    .JoinAlias(() => joinedEan.CtEnergietype, () => joinedEnergieType)
    .JoinAlias(() => uitgaandebrief.BRIEFBESTEMMELINGENCollection, () => joinedBriefBestemmeling)
    .JoinAlias(() => uitgaandebrief.CtBriefType, () => joinedBriefType)
    .JoinAlias(() => uitgaandebrief.CtBriefStatus, () => joinedBriefStatus)
    .JoinAlias(() => joinedBriefBestemmeling.CONTACTPERSOONCollection, () => joinedContactpersoon, JoinType.LeftOuterJoin)
    .JoinAlias(() => joinedBriefBestemmeling.CtContactPersoonType, () => joinedBestemmelingType, JoinType.LeftOuterJoin)
    .JoinAlias(() => joinedBriefBestemmeling.CtVerzendModus, () => joinedVerzendModus, JoinType.LeftOuterJoin)
    .JoinAlias(() => joinedContactpersoon.CtContactpersoonType, () => joinedContactpersoonType, JoinType.LeftOuterJoin)
    .JoinAlias(() => joinedContactpersoon.CtTaal, () => joinedContactpersoonTaal, JoinType.LeftOuterJoin)
    .JoinAlias(() => joinedContactpersoon.TOEWIJZVERBRUIKVERANTCollection, () => joinedVerbruiksVerantw, JoinType.LeftOuterJoin)
    .JoinAlias(() => joinedContactpersoon.CtProfielGroep, () => joinedProfielGroep, JoinType.LeftOuterJoin);

这只是开始。下面是过滤结果的部分(当需要时)。

if (briefType.HasValue)
{
    baseQuery.Where(() => uitgaandebrief.BriefType == briefType.Value);
}
if (verzendModus.HasValue)
{
    baseQuery.Where(() => joinedBriefBestemmeling.VerzendModus == verzendModus.Value);
}
if (!string.IsNullOrEmpty(binnenland) && binnenland.Trim() != "-1")
{
    baseQuery.Where(() => joinedBriefBestemmeling.BinnenLand == binnenland.ToBoolean());
}

然后我得到了部分来选择我需要的东西,并将其翻译成DTO (NieuwePrintopdrachtenInfo)。

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

是的,我知道这是一个烂摊子。既然你走了这么远,你会很高兴知道我们快到了。这是我用来返回结果的代码(它是通用的,并使用我在这里找到的DeepTransform)

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

编辑

在Radim Köhler的帮助帖子之后,我发现一个小组不会帮助我解决我的问题。这就是为什么我要解释真正的问题。在代码中,前面的查询是用Skip &以分页为例。在我的情况下,当执行查询时,我得到50个结果。这50个结果包含重复,需要通过uitgaandbrefid进行分组。这就是为什么最初的开发人员编写了这段代码,当结果从DB返回时执行。

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

这段代码仍然可以工作,但是只能得到32个结果。这导致我的页面永远不会包含50个结果。最初的开发人员使用服务器端分页而不是在DB上进行分页,所以他从来没有遇到过这个问题(性能方面这是一个巨大的问题)。这就是为什么我重构了它,使它执行得更快,但这导致不能得到精确的50个结果。我想我需要添加一个独特的然后,但我不知道我如何得到这个工作在NHibernate,因为我习惯了与EntityFramework

Nhibernate Group By and Alias To Bean

一般来说,如果我们想要将我们的投影更改为使用GROUP BY,我们必须将所有"SELECT"部分更改为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)替换原始代码。但我们可以做更多,我们可以引入这些(只是一个快速版本)扩展方法(只是一个简单的版本,真的-但工作)

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)
    ...
IsNull()也是扩展名