我一直在努力将旧的查询翻译成Nhibernate。 我们正在将旧项目从Nhibernate 2升级到最新版本。 我正在使用QueryOver语法,因为Linq不是一个选项,因为查询的复杂性(同事的建议)。
我想查询DB(Oracle)以获得一些必须分组的结果。 结果我需要一个我的DTO的分组集合。我也注意到nhibernate无法转换为具有复杂属性的DTO(嵌套DTO) 为了解决这个问题,我找到了this主题。这很好用,但我不是魔术弦的粉丝......
我将添加一些代码片段,说明我的怪物查询在这一刻的表现。 问题是我似乎无法弄清楚如何在不破坏其他所有内容的情况下添加组。所以我想要对一个属性进行分组,但仍然在我的结果中有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")));
是的,我知道这是一团糟。既然你已经做到了这一点,你会很高兴知道我们几乎就在那里。这是我用来返回结果的代码(它是通用的并使用我发现的here的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>();
}
修改
在RadimKöhler的有用帖子之后,我发现一群人不会帮助我解决我的问题。这就是为什么我会解释真正的问题。 在代码中,先前的查询是使用Skip&amp; amp;来构建和扩展的。用于寻呼目的。在我的情况下,我在执行查询时得到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);
此代码仍然有效,但只能获得32个结果。这会导致我的页面永远不会包含50个结果。最初的开发人员使用服务器端分页而不是在数据库上进行,因此他从来没有遇到过这个问题(性能明智这是一个很大的问题)。这就是为什么我重构它以便它会更快地执行,但这导致不会获得50个结果。 我想我需要添加一个独特的但我不知道如何让它在NHibernate中工作,因为我习惯使用EntityFramework。
答案 0 :(得分:3)
一般情况下,如果我们想要将我们的投影更改为使用GROUP BY,我们必须将所有“SELECT”部分更改为GROUP BY或SUM,MIN ... <的一部分/ p>
我们可以用这种语法
来做到这一点// 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()也是扩展名