在NHibernate实体内执行查询

时间:2014-08-26 20:10:56

标签: c# sql .net linq nhibernate

我有一个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的{​​{1}}属性被映射为_games

Bag

以下代码的工作正常,但是,NHibernate在游戏表上执行非常天真的谓词,并在内存中执行排序和过滤。

Bag<Game>("_games", m =>
{
    m.Key(k => k.Column("PinballMachineID"));
    m.Access(Accessor.Field);
    m.Cascade(Cascade.All);
}, r => r.OneToMany()); 

这非常不理想,因为当我需要的是10时,数据库正在传输数百万条记录。

理想情况下,我希望NHibernate生成如下所示的查询:

-- SLOW! 1,000,000 records

SELECT ...
FROM Games
WHERE PinballMachineID = 123

是否可以配置我的映射,以便我可以在水合物体上执行其他查询(在数据库上)。

我知道我可以使用NHibernate会话来执行linq查询,但我希望这个逻辑成为我的实体的一部分

2 个答案:

答案 0 :(得分:2)

不幸的是,NHibernate并不支持这一点。

当您为PinballMachine创建映射时,您在ID列上定义了一对多关系,该关系会(懒洋洋地或急切地)获取所有匹配的Game实体。

我建议的一件事是GetTop10Games看起来应该属于一个存储库类,而不是该实体的成员。这是使用存储库模式背后的原因之一 - 它封装了所有数据访问逻辑,反过来甚至允许您在真正需要时编写特定的高性能查询,每隔一段时间。这是(不幸或不幸)大多数ORM框架的问题;你永远不知道什么时候某个LINQ提供程序表现不佳,甚至根本无法转换为SQL,所以你想保持你的选项开放。

我肯定会让此方法成为IGameRepositoryIPinballMachineRepository的成员,并实现类似:

public IList<Games> GetTopGamesForMachine(PinballMachine machine, int maxItems)
{
     return Session
         .Query<Games>()
         .Where(g => g.PinballMachine == machine)
         .OrderByDescending(g => g.Score)
         .Take(maxItems)
         .ToList();
}

答案 1 :(得分:1)

看来,从NHibernate 5开始,已接受的答案是“不幸的是,NHibernate不支持该答案。”不再正确:

  

从NHibernate 5.0开始,还可以使用System.Linq命名空间中的标准Linq扩展名AsQueryable从实体集合创建查询。

IList<Cat> whiteKittens =
    cat.Kittens.AsQueryable()
        .Where(k => k.Color == "white")
        .ToList();
     

https://nhibernate.info/doc/nhibernate-reference/querylinq.html

尽管我一直在尝试真的使其切实可行,但是对于NHibernate ORM的“持久性无知”的实用性,我无法确切地说出2019年与2014年之间的其余答案和评论。尽可能...我们会看到的。