使用 NHibernate 在最后一个节点中过滤 属性 上的嵌套模型
Filter nested models on property in last node with NHibernate
我正在使用带有代码映射的 NHibernate。
我有三个模型:解决方案、安装和系统。它们之间是一对多的关系。这样每个解决方案都有一个安装列表,每个安装都有一个系统列表。
每个系统都有一个属性 "Type",可以是“1”或“0”。
我正在尝试在解决方案存储库中编写一个方法,该方法将 return 所有解决方案,其安装仅包含“1”类型的系统。
我已经尝试了 SystemMap 中的 Where 关键字,但使用和不使用它得到的结果都是一样的。然后我用 QueryOver(???) 尝试了几个不同的实验但没有成功。
我该如何过滤最后一个节点中的信息?
感谢您的回答,我已经完成了以下实施,但它产生了大量的系统和解决方案。也许我做错了什么?
地图如下:
public SAPSolutionMap()
{
Id(t => t.YPID);
Property(e => e.ShortName);
Property(e => e.FullName);
Bag(x => x.SapInstallations, colmap =>
{
colmap.Table("SAPInstallation");
colmap.Key(x => x.Column("Solution"));
colmap.Inverse(true);
colmap.Lazy(CollectionLazy.NoLazy);
colmap.Fetch(CollectionFetchMode.Join);
colmap.Cascade(Cascade.None);
}, map => map.OneToMany(m => m.Class(typeof(SAPInstallation))));
}
public SAPInstallationMap()
{
Id(t => t.InstallationNumber);
Bag(x => x.SapSystems, colmap =>
{
colmap.Table("sapgui");
colmap.Key(x => x.Column("Installation"));
colmap.Inverse(true);
colmap.Lazy(CollectionLazy.NoLazy);
colmap.Cascade(Cascade.None);
colmap.Fetch(CollectionFetchMode.Join);
//colmap.Where("Type = 1");
}, map => map.OneToMany(m => m.Class(typeof(SAPSystem))));
ManyToOne(x => x.SapSolution, map =>
{
map.Column("Solution");
map.NotNullable(true);
map.Cascade(Cascade.None);
map.Class(typeof(SAPSolution));
});
}
public SAPSystemMap()
{
Id(t => t.ID, t => t.Generator(Generators.Identity));
Property(e => e.Type);
Property(e => e.ExplanationText);
ManyToOne(x => x.SapInstallation, map =>
{
map.Column("Installation");
map.NotNullable(true);
map.Cascade(Cascade.None);
map.Class(typeof(SAPInstallation));
});
}
查询:
public IList<SAPSolution> GetProductionSystems()
{
SAPSystem syst = null;
SAPInstallation installation = null;
var subquery = QueryOver.Of(() => syst)
.JoinQueryOver(x => x.SapInstallation, () => installation)
.Where(() => syst.Type == 1)
.Select(x => installation.SapSolution.YPID);
// main Query
var query = Session.QueryOver<SAPSolution>()
.WithSubquery
.WhereProperty(root => root.YPID)
.In(subquery);
return query.List<SAPSolution>();
}
谢谢!
一般的解决方案应该是:
// this is a subquery (SELECT ....
System syst = null;
Installation installation = null;
var subquery = QueryOver.Of(() => syst)
.JoinQueryOver(x => x.Installation, () => installation)
.Where(() => syst.Type == 1)
.Select(x => installation.Solution.ID)
;
// main Query
var query = session.QueryOver<Solution>()
.WithSubquery
.WhereProperty(root => root.ID)
.In(subquery)
;
var list = query
.Take(10)
.Skip(10)
.List<Solution>();
我们可以看到,解决方案、安装和系统
System
有 属性 Installation
(many-to-one
)
Installation
有 属性 Solution
(many-to-one
)
这是可以预料的,因为它与一对多并行(它是反向映射)
因此,然后我们创建 subquery
,其中 returns 只是属于具有搜索类型的系统的解决方案 ID。
主查询是扁平的(最大的好处),我们可以在其上使用分页。
即使只有一种方法(一对多),我们也能做到。但这会生成更复杂的 SQL 查询......并且没有意义。在 C# 中,我们可以同时拥有这两种关系...
延长:
你做得很好。您的映射和查询真的很酷。但是有一个很大的问题:LAZY 是我们 should/MUST 使用的。检查这个:
NHibernate is lazy, just live with it, 来自 Ayende
因此,我们的集合不能通过 JOIN 获取,因为这会使结果成倍增加(10 个解决方案 * 100 个安装 * 10 个系统 == 10000 个结果)
Bag(x => x.SapSystems, colmap =>
{
...
// THIS IS not good way
colmap.Lazy(CollectionLazy.NoLazy);
colmap.Fetch(CollectionFetchMode.Join);
我们应该尽可能使用LAZY。为了避免后面的 1 + N 问题,我们可以使用批量获取(例如检查这个)
- How to Eager Load Associations without duplication in NHibernate?
所以,我们的集合应该这样映射:
Bag(x => x.SapSystems, colmap =>
{
...
// THIS IS not good way
colmap.Lazy(CollectionLazy.Lazy);
colmap.BatchSize(100);
使用此设置,查询将真正仅使用根对象,相关集合将非常有效地加载
我正在使用带有代码映射的 NHibernate。
我有三个模型:解决方案、安装和系统。它们之间是一对多的关系。这样每个解决方案都有一个安装列表,每个安装都有一个系统列表。
每个系统都有一个属性 "Type",可以是“1”或“0”。
我正在尝试在解决方案存储库中编写一个方法,该方法将 return 所有解决方案,其安装仅包含“1”类型的系统。
我已经尝试了 SystemMap 中的 Where 关键字,但使用和不使用它得到的结果都是一样的。然后我用 QueryOver(???) 尝试了几个不同的实验但没有成功。
我该如何过滤最后一个节点中的信息?
感谢您的回答,我已经完成了以下实施,但它产生了大量的系统和解决方案。也许我做错了什么?
地图如下:
public SAPSolutionMap()
{
Id(t => t.YPID);
Property(e => e.ShortName);
Property(e => e.FullName);
Bag(x => x.SapInstallations, colmap =>
{
colmap.Table("SAPInstallation");
colmap.Key(x => x.Column("Solution"));
colmap.Inverse(true);
colmap.Lazy(CollectionLazy.NoLazy);
colmap.Fetch(CollectionFetchMode.Join);
colmap.Cascade(Cascade.None);
}, map => map.OneToMany(m => m.Class(typeof(SAPInstallation))));
}
public SAPInstallationMap()
{
Id(t => t.InstallationNumber);
Bag(x => x.SapSystems, colmap =>
{
colmap.Table("sapgui");
colmap.Key(x => x.Column("Installation"));
colmap.Inverse(true);
colmap.Lazy(CollectionLazy.NoLazy);
colmap.Cascade(Cascade.None);
colmap.Fetch(CollectionFetchMode.Join);
//colmap.Where("Type = 1");
}, map => map.OneToMany(m => m.Class(typeof(SAPSystem))));
ManyToOne(x => x.SapSolution, map =>
{
map.Column("Solution");
map.NotNullable(true);
map.Cascade(Cascade.None);
map.Class(typeof(SAPSolution));
});
}
public SAPSystemMap()
{
Id(t => t.ID, t => t.Generator(Generators.Identity));
Property(e => e.Type);
Property(e => e.ExplanationText);
ManyToOne(x => x.SapInstallation, map =>
{
map.Column("Installation");
map.NotNullable(true);
map.Cascade(Cascade.None);
map.Class(typeof(SAPInstallation));
});
}
查询:
public IList<SAPSolution> GetProductionSystems()
{
SAPSystem syst = null;
SAPInstallation installation = null;
var subquery = QueryOver.Of(() => syst)
.JoinQueryOver(x => x.SapInstallation, () => installation)
.Where(() => syst.Type == 1)
.Select(x => installation.SapSolution.YPID);
// main Query
var query = Session.QueryOver<SAPSolution>()
.WithSubquery
.WhereProperty(root => root.YPID)
.In(subquery);
return query.List<SAPSolution>();
}
谢谢!
一般的解决方案应该是:
// this is a subquery (SELECT ....
System syst = null;
Installation installation = null;
var subquery = QueryOver.Of(() => syst)
.JoinQueryOver(x => x.Installation, () => installation)
.Where(() => syst.Type == 1)
.Select(x => installation.Solution.ID)
;
// main Query
var query = session.QueryOver<Solution>()
.WithSubquery
.WhereProperty(root => root.ID)
.In(subquery)
;
var list = query
.Take(10)
.Skip(10)
.List<Solution>();
我们可以看到,解决方案、安装和系统
System
有 属性Installation
(many-to-one
)Installation
有 属性Solution
(many-to-one
)
这是可以预料的,因为它与一对多并行(它是反向映射)
因此,然后我们创建 subquery
,其中 returns 只是属于具有搜索类型的系统的解决方案 ID。
主查询是扁平的(最大的好处),我们可以在其上使用分页。
即使只有一种方法(一对多),我们也能做到。但这会生成更复杂的 SQL 查询......并且没有意义。在 C# 中,我们可以同时拥有这两种关系...
延长:
你做得很好。您的映射和查询真的很酷。但是有一个很大的问题:LAZY 是我们 should/MUST 使用的。检查这个:
NHibernate is lazy, just live with it, 来自 Ayende
因此,我们的集合不能通过 JOIN 获取,因为这会使结果成倍增加(10 个解决方案 * 100 个安装 * 10 个系统 == 10000 个结果)
Bag(x => x.SapSystems, colmap =>
{
...
// THIS IS not good way
colmap.Lazy(CollectionLazy.NoLazy);
colmap.Fetch(CollectionFetchMode.Join);
我们应该尽可能使用LAZY。为了避免后面的 1 + N 问题,我们可以使用批量获取(例如检查这个)
- How to Eager Load Associations without duplication in NHibernate?
所以,我们的集合应该这样映射:
Bag(x => x.SapSystems, colmap =>
{
...
// THIS IS not good way
colmap.Lazy(CollectionLazy.Lazy);
colmap.BatchSize(100);
使用此设置,查询将真正仅使用根对象,相关集合将非常有效地加载