NHIbernate 3.0 - QueryOver, с использованием той же проекции с отчетливой ошибкой и ошибками в SQL-запросах - PullRequest
2 голосов
/ 05 декабря 2011

У меня есть NHibernate QueryOver, который генерирует ошибку sql: Элементы ORDER BY должны появляться в списке выбора, если указано SELECT DISTINCT

Проблема вызвана SQL-проекцией Iиспользую чтобы выбрать, где и упорядочить.Поскольку сама проекция использует функцию sql, у нее есть параметры (константа: пробел).

При использовании проекции, назначенной переменной, NH переводит каждое использование этой переменной уникально в sql, что означает, что каждое получает своеновый параметр sql.Sql поэтому думает, что заявления разные.Я пытался безрезультатно использовать псевдонимы для проекций, но, похоже, нет способа сделать это с помощью QueryOver.

Потеряно для идей, отличных от возврата к API Criteria.

Этоупрощенный код QueryIOver:

  var projection = ContactOrCompanyName();
  return Session.QueryOver<Contact>()
    .Select(
      Projections.Distinct(
        Projections.ProjectionList()
          .Add(Projections.Property<Contact>(x => x.Id).As("ContactId"))
          .Add(projection)
        )
    )
    .TransformUsing(Transformers.AliasToBean<ContactDto>())
    .OrderBy(projection).Asc;

private IProjection ContactOrCompanyName
    {
      get
      {
        return Projections.SqlFunction(
          "coalesce",
          NHibernateUtil.String,
          Projections.Property<Contact>(c => c.CompanyName),
          Projections.SqlFunction(
            "concat",
            NHibernateUtil.String,
            Projections.Property<Contact>(c => c.FirstName),
            Projections.Constant(" "),
            Projections.Property<Contact>(c => c.LastName)
          )
        );
      }
    }

приводит к следующему sql:

SELECT distinct   
this_.CONTACT_ID as y0_, 
coalesce(this_.COMPANY_NM, (this_.FIRST_NM+@p0+this_.LAST_NM)) as y1_ 
FROM dbo.ADD_CONTACT this_ 
ORDER BY coalesce(this_.COMPANY_NM, (this_.FIRST_NM+@p1+this_.LAST_NM)) asc

Похоже, что Criteria API действительно поддерживает повторное использование псевдонимов в этом примере:

IList results = session.CreateCriteria(typeof(DomesticCat), "cat")
    .CreateAlias("kittens", "kit")
    .SetProjection( Projections.ProjectionList()
        .Add( Projections.Property("cat.Name"), "catName" )
        .Add( Projections.Property("kit.Name"), "kitName" )
    )
    .AddOrder( Order.Asc("catName") )
    .AddOrder( Order.Asc("kitName") )
    .List();

Так где же это в QueryOver?

1 Ответ

3 голосов
/ 05 декабря 2011

Это немного глупо, но работает.Создав две проекции, одну для сравнения и одну для выбора, мы можем не допустить, чтобы SQL жаловался на порядок, поскольку проекция не включена в список выбора:

      CompanyDirectorDto dtoAlias = null;
      var contactsQuery = Session.QueryOver<Contact>()
        .Select(
          Projections.Distinct(
            Projections.ProjectionList()
              .Add(Projections.Property<Contact>(x => x.Id).WithAlias(() => dtoAlias.ContactId))
              .Add(ContactOrCompanyNameComparer)
              .Add(ContactOrCompanyNameSelector.WithAlias(() => dtoAlias.ContactDisplayName))
            )
        )
        .TransformUsing(Transformers.AliasToBean<CompanyDirectorDto>())
        .OrderBy(ContactOrCompanyNameComparer).Asc;

private IProjection ContactOrCompanyNameSelector
{
  get
  {
    return Projections.SqlFunction(
      "coalesce",
      NHibernateUtil.String,
      Projections.Property<Contact>(c => c.CompanyName),
      Projections.SqlFunction(
        "concat",
        NHibernateUtil.String,
        Projections.Property<Contact>(c => c.FirstName),
        Projections.Constant(" "),
        Projections.Property<Contact>(c => c.LastName)
      )
    );
  }
}

private IProjection ContactOrCompanyNameComparer
{
  get
  {
    return Projections.SqlFunction(
      "coalesce",
      NHibernateUtil.String,
      Projections.Property<Contact>(c => c.CompanyName),
      Projections.SqlFunction(
        "concat",
        NHibernateUtil.String,
        Projections.Property<Contact>(c => c.FirstName),
        Projections.Property<Contact>(c => c.LastName)
      )
    );
  }
}
...