Mappare l'entità usando la query in ibernazione
-
05-07-2019 - |
Domanda
considera la tabella
sales (id, seller_id, amount, date)
e qui è una vista che viene generata da sales
utilizzando la query SELECT seller_id, SUM (importo) DA sales GROUP BY seller_id
total_sales (seller_id, amount)
Voglio creare un'entità per le vendite totali ma senza la vista sul lato sql.
Questa entità sarà costruita da una query. La cosa più vicina che ho trovato è this , ma non sono riuscito a farlo funzionare.
Anche se definisco il caricatore, l'ibernazione cerca la tabella dell'entità e genera un errore se non riesce a trovarlo. Se creo la tabella, non carica l'entità dalla query denominata che ho definito, Hibernate genera la query stessa.
C'è un modo per far funzionare @Loader o c'è un altro modo in cui posso mappare una query sull'entità?
Soluzione
Perché non usi semplicemente new
nella query?
select new TotalSales(seller_id, count(seller_id))
from sales
group by seller_id
Devi solo scrivere una classe TotalSales con un costruttore che prende il seller_id e un numero intero.
Modifica : quando si utilizza l'API dei criteri, è possibile utilizzare AliasToBeanResultTransformer
(vedere documenti API ). Copia ogni nome di alias in una proprietà con lo stesso nome.
List list = s.createCriteria(Sales.class)
.setProjection(Projections.projectionList()
.add( Projections.property("id"), "SellerId" )
.add( Projections.rowCount("id"), "Count" ) )
.setResultTransformer(
new AliasToBeanResultTransformer(TotalSales.class) )
.list();
Quindi il tuo TotalSales
ha bisogno di una proprietà SellerId
e Count
.
Altri suggerimenti
Oltre alla risposta di Stefan, puoi anche utilizzare una query HQL esplicita per
SELECT seller_id, SUM(amount) FROM sales GROUP BY seller_id
Il risultato è naturalmente archiviato in Elenco. Se questo tipo di dati non è conveniente per te, potresti:
- crea nuovi oggetti TotalSale con loro (usa probabilmente la risposta di Stefan sarebbe meglio)
- crea una mappa per archiviare i dati (puoi anche incorporarlo direttamente nella richiesta).
Puoi provare a definire un caricatore personalizzato. Non l'ho mai usato, ma sembra ragionevole:
<sql-query name="totalSale">
<return alias="ts" class="TotalSale" />
SELECT seller_id as {ts.seller_id}, SUM(amount) as ts.amount
FROM sales
WHERE seller_id = ?
GROUP BY seller_id
</sql-query>
Non sono sicuro se è necessario il filtro su seller_id.
Fai riferimento a questa query denominata in un mapping di classe:
<class name="TotalSale">
<id name="seller_id">
<generator class="increment"/>
</id>
<property name="seller_id" />
<property name="amount" />
<loader query-ref="totalSale"/>
</class>
Ci sono maggiori dettagli in il manuale .
In alternativa, è possibile utilizzare direttamente una query del nome dal codice, in questo modo non è necessario un mapping di TotalSale e non è necessario scrivere la query nel codice. Le query con nome possono anche restituire oggetti. Vedi dettagli sulle query con nome nella documentazione.
se vuoi davvero un'entità specifica solo per questo lavoro puoi usare una "formula" su una proprietà personalizzata
<class name="SellerSales" table="Sales" lazy="true">
<id name="SellerId" column="SellerId" type="int">
<generator class="native" />
</id>
<property name="SalesSum" type="float" update="false" insert="false"
formula="select SUM(sal.ammount) from sales sal where sal.seller_id = SellerId)" />
</class>
public class SellerSales
{
public int SellerId {get; set;}
public float SalesSum {get; set;}
}
in quanto tale è accessibile al motore dei criteri per ordini, restrizioni ecc. che ritengo sia il motivo per cui si desidera utilizzarlo.