NHibernate - три двунаправленных отношения между тремя классами дают N + 1 - PullRequest
0 голосов
/ 11 июля 2011

У меня немного сложная объектная модель, которая образует треугольник. Существует User сущность, которая имеет коллекции Items и Taxonomies. Item также имеет таксономию. И для удобства я хотел, чтобы Item и Taxonomy знали его владельца и Taxonomy знали его Item, если таковые имеются. Смотрите схему:

diagram

Так что получается три двунаправленных отношения. Моя проблема в том, что когда я сопоставляю его в NHibernate таким образом и запрашиваю пользователя с заданным идентификатором, я получаю Выбрать N + 1 проблему.

Сначала User загружается с нетерпением Items. Затем Taxonomies загружаются с подключенными к нему нетерпеливо Item. И это как ожидалось и как определено в отображениях. Но теперь есть N + 1 запрос для загрузки Items, связанный с Taxonomies.

queries

Это избыточно, так как все части графа объектов уже загружены. Эта проблема исчезает, когда я делаю свое отношение User-Item однонаправленным со стороны User (как и ожидалось, есть только 2 запроса), но я не хочу удалять это обратное отношение. Можно ли получить оптимальную выборку при всех трех отношениях двунаправленного?

Вот мои части картирования:

public class UserOverride : IAutoMappingOverride<User>
{
    public void Override(AutoMapping<User> mapping)
    {
        mapping.HasMany(x => x.Items).Inverse()
            .Not.LazyLoad().Fetch.Join();
        mapping.HasMany(x => x.Taxonomies).Inverse()
            .LazyLoad().Fetch.Select();
    }
}

public class ItemOverride : IAutoMappingOverride<Item>
{
    public void Override(AutoMapping<Item> mapping)
    {
        mapping.References(x => x.Taxonomy); // many-to-one
    }
}

public class TaxonomyOverride : IAutoMappingOverride<Taxonomy>
{
    public void Override(AutoMapping<Taxonomy> mapping)
    {
        mapping.HasOne(x => x.Item).PropertyRef(x => x.Taxonomy)
            .Not.LazyLoad().Fetch.Join();
    }
}

И я запрашиваю свою базу данных самым простым способом:

var user = session.Get<User>(1);

1 Ответ

1 голос
/ 11 июля 2011

Поскольку сопоставления будут влиять на все запросы, я предпочитаю придерживаться правила, согласно которому сопоставления следует изменять только для быстрой загрузки, если объект НИКОГДА не используется без другого объекта.В вашей ситуации, если вы когда-нибудь просто захотите пользователей и можете меньше заботиться об элементе и записях таксономии, вы будете выполнять дополнительную работу с базой данных без какой-либо выгоды.

Я бы посоветовал вам выполнить загрузку через другой маршрут - в вашем запросе.

Session.QueryOver<User>().Where(u => u.Id == 1)
    .join.QueryOver<Items>(u => u.Items)
    .Join.QueryOver<Taxonomy>(i => i.Taxonomy)
    .TransformUsing(Trasnformers.DistinctRootEntity);
...