2013-09-04 23 views
6

C'è un modo per convertire questa istruzione SQL in un criterio di NHibernate?Criteri SQL Union a NHibernate

(select b1.FieldA as Name, b1.FieldA as FullName from Sale b1 where b1.FieldA like '%john%' or b1.FieldA like '%john%' order by b1.Id desc) 
union 
(select b2.FieldC as Name, b2.FieldD as FullName from Sale b2 where b2.FieldC like '%john%' or b2.FieldD like '%john%' order by b2.Id desc) 
union 
(select c.FieldE as Name, c.FieldF as FullName from Client c where c.FieldE like '%john%' or c.FieldF like '%john%' order by c.Id desc) 

Ho trovato che NHibernate non supporta i sindacati.

+1

Si può vedere l'answear qui: http://stackoverflow.com/questions/8591200/union-with-nhibernate-and-criteria – Cesar

risposta

3

Quindi, ho trovato due soluzioni. Eseguo ogni query separatamente rispetto a concatenare i risultati. È come un sindacato, ma non viene eseguito nel DB, viene eseguito in memoria.

var b1 = Session.Query<Sale>() 
      .Where(x => x.FiledA.Contains(filter) || x.FiledB.Contains(filter)) 
      .OrderBy(x => x.Id) 
      .GroupBy(x => new { x.FiledA, x.FiledB }) 
      .Select(x => new Foo { FullName = x.Key.FiledA, Name = x.Key.FiledB }) 
      .Take(30) 
      .ToList(); 

var b2 = Session.Query<Sale>() 
      .Where(x => x.FiledC.Contains(filter) || x.FiledD.Contains(filter)) 
      .OrderBy(x => x.Id) 
      .GroupBy(x => new {x.FiledC, x.FiledD}) 
      .Select(x => new Foo {FullName = x.Key.FiledC, Name = x.Key.FiledD}) 
      .Take(30) 
      .ToList(); 


var c = Session.Query<Client>() 
      .Where(x => x.FiledE.Contains(filter) || x.FiledF.Contains(filter)) 
      .OrderBy(x => x.Id) 
      .GroupBy(x => new { x.FiledE, x.FiledF }) 
      .Select(x => new Foo { FullName = x.Key.FiledE, Name = x.Key.FiledF }) 
      .Take(30) 
      .ToList(); 

return b1.Concat(b2) 
     .Concat(c) 
     .ToList() 
     .GroupBy(x => new { x.Name, x.FullName }) 
     .Select(x => x.First()) 
     .Take(30); 

O

var b1 = Session.CreateCriteria<Sale>() 
    .SetProjection(Projections.ProjectionList() 
     .Add(Projections.Distinct(Projections.Property("FiledA")), "Name") 
     .Add(Projections.Property("FiledB"), "FullName")) 
    .Add(Restrictions.Or(Restrictions.InsensitiveLike("FiledA", filter), 
     Restrictions.InsensitiveLike("FiledB", filter))) 
    .AddOrder(Order.Desc("Id")) 
    .SetMaxResults(30) 
    .SetResultTransformer(Transformers.AliasToBean<Foo>()) 
    .List<Foo>(); 

var b2 = Session.CreateCriteria<Sale>() 
    .SetProjection(Projections.ProjectionList() 
     .Add(Projections.Distinct(Projections.Property("FiledC")), "Name") 
     .Add(Projections.Property("FiledD"), "FullName")) 
    .Add(Restrictions.Or(Restrictions.InsensitiveLike("FiledC", filter), 
     Restrictions.InsensitiveLike("FiledD", filter))) 
    .AddOrder(Order.Desc("Id")) 
    .SetMaxResults(30) 
    .SetResultTransformer(Transformers.AliasToBean<Foo>()) 
    .List<Foo>(); 

var c = Session.CreateCriteria<Client>() 
    .SetProjection(Projections.ProjectionList() 
     .Add(Projections.Distinct(Projections.Property("FiledE")), "Name") 
     .Add(Projections.Property("FieldF"), "FullName")) 
    .Add(Restrictions.Or(Restrictions.InsensitiveLike("FiledE", filter), 
     Restrictions.InsensitiveLike("FieldF", filter))) 
    .AddOrder(Order.Desc("Id")) 
    .SetMaxResults(30) 
    .SetResultTransformer(Transformers.AliasToBean<Foo>()) 
    .List<Foo>(); 

return b1.Concat(b2) 
     .Concat(c) 
     .ToList() 
     .GroupBy(x => new {x.FullName, x.Name}) 
     .Select(x => x.First()) 
     .Take(30); 
+1

si carica gli oggetti in memoria quindi unione. Puoi unire prima di caricare gli oggetti in memoria? in tal caso, SQL Query può rimuovere qualsiasi duplicazione o se è necessario applicare ulteriori Fetches che potrebbero funzionare correttamente. –

+0

Union non è ancora supportato da NHibernate linq al momento della stesura di questo. Preso il set di risultati è abbastanza piccolo dovrebbe andare bene per l'unione in memoria, altrimenti preferirei usare una query denominata. –

2

Prova a utilizzare una vista. Può essere mappato direttamente in NHibernate e non si basa su un'implementazione specifica del database. È necessario rimuovere le clausole where e quindi è possibile creare i criteri NHibernate rispetto a "Name" e "FullName".

(select b1.FieldA as Name, b1.FieldA as FullName from Sale b1 order by b1.Id desc) 
    union 
    (select b2.FieldC as Name, b2.FieldD as FullName from Sale b2 order by b2.Id desc) 
    union 
    (select c.FieldE as Name, c.FieldF as FullName from Client c order by c.Id desc)