Получение данных из всех таблиц вместо одной с HQL-запросом, который должен получить только данные одной таблицы - PullRequest
3 голосов
/ 16 января 2010

Я создал 3 таблицы в своей базе данных и поместил в них данные. Все 3 таблицы имеют внешние ключи, соединяющие их вместе. Ниже приведены таблицы классов и там сопоставления. Когда я выполняю запрос, указанный в конце, я получаю IList <> объектов, и они имеют данные из всех 3 таблиц. Однако мой HQL-запрос только из самой верхней таблицы. Как я могу получить только результаты из самой верхней таблицы?

Это мои занятия:

public class Technology
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual int SortOrder { get; set; }
    public virtual string Abbreviation { get; set; }
    public virtual IList<TechnologyDescription> TechnologyDescriptions { get; private set; }

    public Technology()
    {
        TechnologyDescriptions = new List<TechnologyDescription>();
    }

    public virtual void AddTechnologyDescription(TechnologyDescription technologyDescription)
    {
        technologyDescription.Technology = this;
        TechnologyDescriptions.Add(technologyDescription);
    }
}

public class TechnologyDescription
{
    public virtual int Id { get; private set; }
    public virtual Technology Technology { get; set; }
    public virtual string Description { get; set; }
    public virtual DescriptionType DescriptionType { get; set; }
}

public class DescriptionType
{
    public virtual int Id {get; private set;}
    public virtual string Type { get; set; }
}

These are my mapping objects:

public class TechnologyMap : ClassMap<Technology>
{
    public TechnologyMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
        Map(x => x.SortOrder);
        Map(x => x.Abbreviation);
        HasMany(x => x.TechnologyDescriptions)
                .Inverse()
                .Cascade.All();
    }
}

public class TechnologyDescriptionMap  : ClassMap<TechnologyDescription>
{
    public TechnologyDescriptionMap()
    {
        Id(x => x.Id);
        References(x => x.Technology);
        Map(x => x.Description);
        References(x => x.DescriptionType);
    }
}

public class DescriptionTypeMap : ClassMap<DescriptionType>
{
    public DescriptionTypeMap()
    {
        Id(x => x.Id);
        Map(x => x.Type);
    }
}

А это мой код HQL:

IQuery q = session.CreateQuery("from Technology T");
IList technologies = q.List();

Ответы [ 2 ]

1 голос
/ 28 января 2010

Я думаю, что вам нужно, чтобы TechnologyDescription загружались лениво. Таким образом, описания загружаются из базы данных только при обращении к ним (NHibernate выдаст второй запрос БД. Обратите внимание, что в некоторых ситуациях это может привести к N + 1 выборам, и вы можете предпочесть запрос «все сразу» в зависимости от использования. )

По сопоставлениям NHibernate xml по умолчанию используется отложенная загрузка коллекций. В прошлом кажется, что у Fluent NHibernate не было того же значения по умолчанию. Вам нужно добавить .LazyLoad() к отображению.

В последнее время похоже, что ленивая загрузка стала отображением по умолчанию: Является ли поведение по умолчанию в Fluent NHibernate для отложенной загрузки коллекций HasMany ?

1 голос
/ 18 января 2010

Я не знаю, возможно ли это с помощью HQL, но с помощью API критериев NHibernate вы можете сделать это:

ICriteria criteria = session.CreateCriteria (typeof(Technology));

criteria.SetFetchMode ("TechnologyDescriptions", FetchMode.Lazy);

var list = criteria.List<Technology>();

Однако, это, вероятно, не совсем то, что вы хотите. Описание TechnologyDescription не будет получено прямо сейчас, но оно будет получено при обращении к ним (то есть при первом вызове свойства TechnologyDescription).

При работе с NHibernate не следует думать с точки зрения «данных». Скорее, вы должны думать с точки зрения «сущностей».
При извлечении сущности вы хотите извлечь сущность целиком (напрямую или ленивым образом). Невозможно частично извлечь сущность, и это совершенно очевидно; Что должен делать NHibernate с сущностью, которую вы частично извлекли, при попытке сохранить эту сущность?

Что-то еще, что появляется в моей голове: Я полагаю, вы хотите получить технологии, и ничего не связано, потому что вы хотите отобразить их в обзоре или что-то в этом роде? В таком случае вам стоит взглянуть на «Преобразования». Например, вы можете создать дополнительный класс с именем TechnologyView, который выглядит следующим образом:

public class TechnologyView
{
    public int Id
    {
        get;
        private set;
    }

    public string Name
    {
        get;
        private set;
    }

    public string Abbreviation
    {
        get;
        private set;
    }

    private TechnologyView()
    {
       // Private constructor, required for NH
    }

    public TechnologyView( int id, string name, string abbreviation )
    {
       this.Id = id;
       this.Name = name;
       this.Abbreviation = abbreviation;
    }
}

После того, как вы это сделаете, вы должны сообщить NHibernate о существовании этого класса. Это можно сделать, например, импортировав класс в файл hbm.xml. (Я не знаю, как это сделать с помощью Fluent).

<import class="MyNamespace.TechnologyView" />

После этого вы можете создать запрос (используя HQL или Критерии), который извлекает TechnologyView экземпляров. NHibernate достаточно умен, чтобы генерировать производительный SQL-запрос.

с использованием HQL:

IQuery q = s.CreateQuery ("select new TechnologyView (t.Id, t.Name, t.Abbreviation) from Technology t");

с использованием критериев:

ICriteria criteria = s.CreateCriteria (typeof(Technology));
criteria.SetResultTransformer (Transformers.AliasToBean (typeof(TechnologyView));
var result = criteria.List<TechnologyView>();
...