I have a repository of PinballMachines, which returns a hydrated PinballMachine
entity. It has a private property that is a list of games played on that machine.
A pinball machine can possibly have millions of games recorded against it. From a PinballMachine
, I want to get high scorers for display, this is the top 10 game players.
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; }
}
The PinballMachine
's _games
property is mapped as a Bag
.
Bag<Game>("_games", m =>
{
m.Key(k => k.Column("PinballMachineID"));
m.Access(Accessor.Field);
m.Cascade(Cascade.All);
}, r => r.OneToMany());
The following code works behaves properly, however, NHibernate performs a very naive predicate on the games table, and performing the sort and filter in-memory.
-- SLOW! 1,000,000 records
SELECT ...
FROM Games
WHERE PinballMachineID = 123
This is very suboptimal as the database is transmitting millions of records when all I need is 10.
Ideally, I want NHibernate to generate a query that looks like the following:
-- FAST! 10 records
SELECT TOP 10 ...
FROM Games
WHERE PinballMachineID = 123
ORDER BY Score DESC
Is it possible to configure my mapping so I can perform additional queries (on the database) on hydrated objects.
I am aware that I can use the NHibernate session to perform a linq query, but I want this logic to part of my entity instead.