C# Nhibernate Group By和别名为Bean
我一直在努力把一个老问题翻译成Nhibernate。 我们正在将一个旧项目从Nhibernate 2升级到最新版本。 我使用QueryOver语法,因为由于查询的复杂性(同事的建议),Linq不是一个选项 我想查询DB(Oracle)以获得一些必须分组的结果。 因此,我需要一个分组的DTO集合。我还注意到,nhibernate在转换为具有复杂属性的DTO(嵌套DTO)时遇到困难 为了解决这个问题,我找到了一个主题。这很好,但我不是魔术弦的粉丝 我将添加一些代码片段,说明我的monster查询目前的情况。 问题是,我似乎不知道如何在不破坏其他所有内容的情况下添加组。因此,我希望对一个属性进行分组,但结果中仍然包含DTO。比如: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查询目前
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)
...