entidade mapa usando consulta no Hibernate
-
05-07-2019 - |
Pergunta
consideram tabela
sales (id, seller_id, amount, date)
e aqui é uma visão que é gerada a partir sales
usando consulta SELECT seller_id, SUM(amount) FROM sales GROUP BY seller_id
total_sales (seller_id, amount)
Eu quero fazer uma entidade para as vendas totais, mas sem a vista no lado sql.
Esta entidade será construído a partir de uma consulta. A coisa mais próxima que eu encontrei é este , mas eu não poderia fazê-lo funcionar.
Mesmo se eu definir o carregador, hibernate olhares para a mesa da entidade e dá um erro se não puder encontrá-lo. Se eu criar a tabela não carrega a entidade a partir da consulta chamado I definido, Hibernate gera a consulta em si.
Existe uma maneira de fazer @Loader ao trabalho ou há outra maneira que eu possa mapear uma consulta para entidade?
Solução
Por que você não apenas usar new
na consulta?
select new TotalSales(seller_id, count(seller_id))
from sales
group by seller_id
Você só escrever uma TotalSales classe com um construtor que tomam a seller_id e um inteiro.
Editar : Ao usar critérios API, você pode usar o AliasToBeanResultTransformer
(Veja documentação da API ). Ele copia todos os nome de alias para uma propriedade com o mesmo 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();
Em seguida, seu TotalSales
precisa de uma propriedade SellerId
e Count
.
Outras dicas
Além de resposta de Stefan, você também pode usar um HQL explícita consulta para
SELECT seller_id, SUM(amount) FROM sales GROUP BY seller_id
O resultado é naturalmente armazenado em List. Se este tipo de dados não é conveniente para você, você pode:
- criar novos objetos TotalSale com eles (resposta uso de Stefan seria melhor provavelmente)
- Crie um mapa para armazenar os dados (você também pode incorporar este diretamente no pedido).
Você pode tentar definir um carregador personalizado. Eu nunca usei isso, mas parece ser razoável:
<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>
Não tenho certeza se o filtro no seller_id é necessário.
Você referenciar esta consulta nomeada em um mapeamento de classe:
<class name="TotalSale">
<id name="seller_id">
<generator class="increment"/>
</id>
<property name="seller_id" />
<property name="amount" />
<loader query-ref="totalSale"/>
</class>
Há mais detalhes em o manual .
Como alternativa, você pode usar diretamente uma consulta de nome a partir do código, desta forma você não precisa de um mapeamento de TotalSale e não tem que escrever a consulta no código. consultas nomeadas também pode retornar objetos. Veja detalhes sobre o nome consultas na documentação.
Se você realmente quer uma entidade específica apenas para este trabalho que você pode usar uma 'fórmula' em uma propriedade personalizada
<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;}
}
, como tal, a sua acessível para o motor Critérios para a ordem-by de, restrições etc., que eu acho que é a razão que você quer usá-lo.