在NHibernate实体内部执行查询
本文关键字:执行 查询 内部 实体 NHibernate | 更新日期: 2023-09-27 18:19:27
我有一个PinballMachines的存储库,它返回一个水合的PinballMachine
实体。它有一个私人财产,是在那台机器上玩的游戏列表。
弹球机可能会记录数百万场比赛。从PinballMachine
开始,我想获得高分,这是排名前十的游戏玩家。
public class PinballMachine
{
private IList<Game> _games = new List<Game>();
public virtual int ID { get; protected set; }
public virtual IEnumerable<Game> GetTop10Games()
{
return _games
.AsQueryable()
.OrderByDescending(g => g.Score)
.Take(10)
.ToList();
}
}
public class Game
{
public virtual Guid ID { get; protected set; }
public virtual string Name { get; set; }
public virtual int Score { get; set; }
public virtual decimal AmountPaid { get; set; }
}
PinballMachine
的_games
属性被映射为Bag
。
Bag<Game>("_games", m =>
{
m.Key(k => k.Column("PinballMachineID"));
m.Access(Accessor.Field);
m.Cascade(Cascade.All);
}, r => r.OneToMany());
下面的代码运行正常,但是,NHibernate在游戏表上执行了一个非常天真的谓词,并在内存中执行排序和筛选。
-- SLOW! 1,000,000 records
SELECT ...
FROM Games
WHERE PinballMachineID = 123
这是非常次优的,因为数据库正在传输数百万条记录,而我只需要10条。
理想情况下,我希望NHibernate生成一个查询,如下所示:
-- FAST! 10 records
SELECT TOP 10 ...
FROM Games
WHERE PinballMachineID = 123
ORDER BY Score DESC
是否可以配置我的映射,以便我可以对水合对象执行额外的查询(在数据库上)。
我知道我可以使用NHibernate会话来执行linq查询,但我希望此逻辑成为我的实体的一部分。
不幸的是,NHibernate不支持这一点。
当您为PinballMachine
创建映射时,您在ID列上定义了一对多关系,该关系(惰性地或急切地)获取所有匹配的Game
实体。
我建议GetTop10Games
看起来应该属于存储库类,而不是实体的成员。这就是使用存储库模式的原因之一——它封装了所有的数据访问逻辑,反过来甚至允许您在真正需要时每隔一段时间编写特定的性能查询。这是(不幸的是,或者不是)大多数ORM框架的问题;您永远不知道某个LINQ提供程序何时会表现不佳,甚至根本无法转换为SQL,所以您希望保留您的选项。
我当然会让这个方法成为IGameRepository
或IPinballMachineRepository
的成员,并实现它,比如:
public IList<Games> GetTopGamesForMachine(PinballMachine machine, int maxItems)
{
return Session
.Query<Games>()
.Where(g => g.PinballMachine == machine)
.OrderByDescending(g => g.Score)
.Take(maxItems)
.ToList();
}
从NHibernate 5开始,公认的答案"不幸的是,NHibernat不支持"似乎不再正确:
从NHibernate 5.0开始,查询也可以从实体集合中创建,标准的Linq扩展AsQueryable可从System.Linq命名空间中获得。
IList<Cat> whiteKittens = cat.Kittens.AsQueryable() .Where(k => k.Color == "white") .ToList();
https://nhibernate.info/doc/nhibernate-reference/querylinq.html
2019年与2014年相比,关于NHibernate ORM的Persistence Ignorance的实用性,我无法明确地谈论其余的答案和评论,尽管我正在努力让它尽可能地发挥作用。。。我们拭目以待。