nHibernate Future <T>, путаница с порядком загрузки - PullRequest
3 голосов
/ 28 марта 2011

Я могу использовать метод Future<T> совершенно неправильно, но у меня много проблем с пониманием того, как оптимизировать его использование.Итак, вот мой простой пример.

Три объекта, Member, Player, Character

Member {
   Player Player { get; set; }

Player {
   IList<Character> Characters { get; set; }
}

Таким образом, по сути, один участник также является одним игроком, и один игрок имеетмного персонажей.Достаточно просто.(причина этой абстракции состоит в том, чтобы поддерживать Member облегченным, чтобы его можно было использовать только для проверки подлинности и ролей, где более тяжелые данные должны быть присоединены к классу Player.)

Итак,У меня есть метод, в котором я хочу запросить все Character, что Player имеет.Итак, у меня настроен следующий запрос ...

        session.QueryOver<Player>()
            .Fetch(context => context.Characters).Eager
            .Take(1)
            .Future<Player>();

        session.QueryOver<Character>()
            .Future<Character>()
            .Take(10);

        return session.QueryOver<Member>()
            .Where(model)
            .Fetch(context => context.Player).Eager
            .List()
            .Take(1)
            .SingleOrDefault()
            .Player;

Здесь я подумала, что из того, что я понимаю о том, как работает Future<T>, я могу понять (что может быть далеко в том, что она будет загружаться Player (1: 1), который будет выполнять запрос для IList<Character> в той же поездке в базу данных, с пределом 10 результатов. Это займет всего 1 игрока за поездку, 1 участника за поездку и до 10символов за поездку.

Однако nhProf говорит мне, что я использую неограниченный запрос. Может кто-нибудь объяснить мне, что здесь происходит? Я просто неправильно понимаю, как работают эти методы? Или кто-нибудь может привести примерэто немного более жизнеспособно? Я не понимаю HQL, поэтому я не могу использовать метод CreateCriteria.

1 Ответ

10 голосов
/ 29 марта 2011

Три запроса в вашем вопросе сделают следующее:

Запрос 1 возьмет первого игрока, которого сможет найти в базе данных, без каких-либо условий.

Запрос 2 получит первые десять символов, которые он сможет найти, опять же без каких-либо условий.

Запрос 3 выполнит три запроса и возьмет первого участника, соответствующего вашему положению, вместе со связанным игроком и вернет игрока участника.

Если вы хотите выполнить итерацию по символам игрока, NHibernate снова попадет в БД, поскольку символы еще не загружены.

Ваш пример может быть выполнен в одном запросе без Futures, как это:

System.Linq.Expressions.Expression<Func<Member, bool>> model = m => m.Id == 1;
Member mAlias = null;
Player pAlias = null;
Character cAlias = null;

Member member = session.QueryOver<Member>(() => mAlias)
    .JoinAlias(m => m.Player, () => pAlias)
    .Left.JoinAlias(() => pAlias.Characters, () => cAlias)
    .Where(model)
    .List().FirstOrDefault();

Вот пример, который может лучше показать, что может делать Фьючерс. Целью запросов является получение Клиента с id = 1 и всех его заказов, а также деталей и заказов заказов.

Class diagram

Теперь, если мы хотим загрузить Заказы вместе с их деталями и заказами, результирующий запрос даст нам декартово произведение: count(Details) * count(Bookings)

int id = 1;
// define Aliases to use in query and be able to reference joined entities
Customer cAlias = null;
Order oAlias = null;
OrderDetails odAlias = null;
Booking bAlias = null;

// get the Customer and his Orders
var customers = session.QueryOver<Customer>(() => cAlias)
    .Left.JoinAlias(o => o.Orders, () => oAlias)
    .Where(c => c.Id == id)
    .Future<Customer>();

// get the Orders and their Details
var orders = session.QueryOver<Order>(() => oAlias)
    .JoinAlias(o => o.Customer, () => cAlias)
    .Left.JoinAlias(() => oAlias.Details, () => odAlias)
    .Where(() => cAlias.Id == id)
    .Future<Order>();

// get the Orders and their Bookings
var orders2 = session.QueryOver<Order>(() => oAlias)
    .JoinAlias(o => o.Customer, () => cAlias)
    .Left.JoinAlias(() => oAlias.Bookings, () => bAlias)
    .Where(() => cAlias.Id == id)
    .Future<Order>();

var list = customers.ToList();
Customer customer = list.FirstOrDefault();

Order o1 = customer.Orders.FirstOrDefault();
// iterate through the Details 
// normally this would cause N+1 selects, here it doesn't, because we already loaded
foreach (OrderDetails od1 in o1.Details)
{
    decimal d = od1.Quantity;
}

Все мои сопоставления работают с отложенной загрузкой, и я не указывал нетерпеливую загрузку в этих запросах. Тем не менее, когда я запускаю код, я получаю ровно три SQL-запроса за одну поездку без декартовой системы. В этом красота будущего.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...