NHIBERNATE 3.0 - Queryover, usando la stessa proiezione con l'errore SQL distinto e di ordine

StackOverflow https://stackoverflow.com/questions/8385740

  •  28-10-2019
  •  | 
  •  

Domanda

Ho una queryover nhibernate che sta generando l'errore SQL: L'ordine per elementi deve apparire nell'elenco Seleziona se viene specificato Select Distint

Il problema è causato da una proiezione SQL che sto usando per selezionare, dove e ordine. Poiché la proiezione stessa utilizza una funzione SQL, ha parametri (una costante: spazio).

Quando si utilizza la proiezione assegnata a una variabile, NH traduce ogni uso di questa variabile in modo univoco in SQL, il che significa che ognuno ottiene il proprio nuovo parametro SQL. SQL quindi pensa che le dichiarazioni siano diverse. Ho cercato di non riuscire a usare gli alias per le proiezioni, ma non sembra non c'è modo di farlo con queryover.

Un po 'perso per idee diverse dalla deviazione dell'API Criteri.

Questo è il codice queryiover semplificato:

  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)
          )
        );
      }
    }

Risultati nel seguente 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

Criteri API sembra supportare il riutilizzo degli alias in corso da questo esempio:

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();

Allora dov'è in queryover?

È stato utile?

Soluzione

Questo è un po 'hacky, ma funziona. Creando due proiezioni una per il confronto e una per la selezione, possiamo interrompere la lamentazione di SQL sull'ordine mediante proiezione non inclusa nell'elenco Select:

      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)
      )
    );
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top