Выполнение запроса внутри сущностей NHibernate

1

У меня есть репозиторий PinballMachines, который возвращает гидратированный PinballMachine. У этого есть частная собственность, которая является списком игр, играемых на этой машине.

У пинбольной машины могут быть миллионы игр, записанных против нее. Из PinballMachine, я хочу получить высокие PinballMachine для показа, это 10 лучших игроков.

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, но я хочу, чтобы эта логика была частью моей сущности.

  • 0
    Похоже, дубликат этого одного stackoverflow.com/questions/2774095/…
  • 0
    Этот вопрос выглядит так же, как и мой, надеюсь, NHibernate достаточно продвинулся, чтобы поддержать это.
Теги:
linq
nhibernate

1 ответ

2
Лучший ответ

К сожалению, NHibernate этого не поддерживает.

Когда вы создали сопоставление для PinballMachine, вы определили, что отношения "один ко многим" в столбце "Идентификатор", который извлекает (лениво или нетерпеливо) все соответствующие объекты " 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();
}
  • 0
    Я думаю, что вы правы, я пытаюсь использовать подход DDD, имея в виду, что мои сущности имеют некоторое поведение, и я считаю, что в настоящее время это плохой подход, который я использовал, поскольку мои доменные сущности - это те же сущности, которые возвращает NHibernate.
  • 1
    Да, даже с ORM вы не можете полностью игнорировать существование уровня данных и его механизмов. Вам все еще нужно открывать и закрывать сеансы (так же, как это делали бы в ADO.NET), убедиться, что они открыты достаточно долго (доступ к отложенному свойству после закрытия сеанса завершится ошибкой), помните о временных объектах и параллелизме проблемы и т. д. Итак, хотя вы можете абстрагироваться от фактического способа сохранения вещей или иметь совершенно другую схему БД, отличную от модели вашего домена, и даже абстрагировать саму ORM, которую вы используете, из моего опыта вы никогда не должны допускать, чтобы эта утечка ваши сущности.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню