【问题标题】:Map entity using query in Hibernate在 Hibernate 中使用查询映射实体
【发布时间】:2010-11-27 11:28:30
【问题描述】:

考虑表格

sales (id, seller_id, amount, date)

这是使用查询SELECT seller_id, SUM(amount) FROM sales GROUP BY seller_idsales生成的视图

total_sales (seller_id, amount)

我想为总销售额创建一个实体,但在 sql 端没有视图。

此实体将从查询构造。我找到的最接近的东西是 this,但我无法让它工作。

即使我定义了加载器,hibernate 也会查找实体的表,如果找不到它会给出错误。如果我创建表,它不会从我定义的命名查询中加载实体,Hibernate 会自行生成查询。

有没有办法让@Loader 工作,或者有另一种方法可以将查询映射到实体?

【问题讨论】:

  • 您将无法通过自定义加载程序使session.createCriteria(TotalSales.class) 工作。如果没有数据库中的支持对象(表或视图),您不能(也不应该)将其映射为实体。

标签: hibernate hql hibernate-mapping


【解决方案1】:

为什么不在查询中使用new

select new TotalSales(seller_id, count(seller_id))
from sales
group by seller_id

您只需编写一个 TotalSales 类,其中的构造函数采用 Seller_id 和一个整数。


编辑:当使用条件 API 时,您可以使用AliasToBeanResultTransformer(参见API docs)。它将每个别名复制到同名的属性中。

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

那么您的TotalSales 需要SellerIdCount 属性。

【讨论】:

  • 因为我想使用像session.createCriteria(TotalSale.class).list()这样的新实体
  • 在我的标准答案中添加了一个部分。
  • 你给出的答案确实非常好,+1,但这不是我想要的
  • 当我调用 session.createCriteria(Sale.class).list() 或 'session.createQuery('from Sale').list()' 时会发生什么? Hibernate 知道如何将表映射到实体,因此它会获取sales 表中的所有记录。但是因为没有名为total_sales 的表,所以当我使用session.createCriteria(TotalSale.class).list() 时,它不知道如何获取和映射字段。我希望休眠知道将 query 映射到实体。就像在这里完成的一样:mikedesjardins.us/wordpress/2008/06/…
  • 是的,我知道您想这样做。问题是:为什么?你需要解决什么问题?如果您通过查询获取实体,则通常无论如何都无法更新它。因此,您是否使用代码中的查询来获取它并不重要。但是您不会经历所有这些麻烦来使实体的自定义加载正常工作。
【解决方案2】:

除了 Stefan 的回答,您还可以使用显式 HQL 查询来

    SELECT seller_id, SUM(amount) FROM sales GROUP BY seller_id

结果自然存储在List中。如果此数据类型对您不方便, 你可以:

  • 用它们创建新的 TotalSale 对象(使用 Stefan 的答案可能会更好)
  • 创建一个 Map 来存储数据(您也可以将其直接嵌入到请求中)。

【讨论】:

    【解决方案3】:

    您可以尝试定义自定义加载器。我从来没有用过这个,但它似乎是合理的:

    <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>
    

    不确定是否需要对 Seller_id 进行过滤。

    您在类映射中引用此命名查询:

    <class name="TotalSale">
        <id name="seller_id">
            <generator class="increment"/>
        </id>
        <property name="seller_id" />
        <property name="amount" />
        <loader query-ref="totalSale"/>
    </class>
    

    more details in the manual

    或者,您可以直接使用代码中的名称查询,这样您就不需要 TotalSale 的映射,也不必在代码中编写查询。命名查询也可以返回对象。请参阅文档中的details about named queries

    【讨论】:

    • 这对session.createCriteria() 没有任何帮助。
    • 我实际上怀疑在这种情况下是否强烈需要 createCriteria,因此我提出了替代方法。
    【解决方案4】:

    如果您真的只需要一个特定实体来完成这项工作,您可以在自定义属性上使用“公式”

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

    因此,它可以访问 Criteria 引擎以进行排序、限制等,我认为这是您想要使用它的原因。

    【讨论】:

    • 除非“Seller”表存在并且未映射到任何其他实体,否则这将不起作用。如果是这样的话,那么整个问题就没有意义了。
    • 实际上我在帖子中有很多错误,我发布的唯一原因可能是主题启动者有一个想法或提供了一些关于他真正需要的信息。否则 stefan 的回答似乎是正确的
    猜你喜欢
    • 2013-08-15
    • 1970-01-01
    • 2015-04-11
    • 2018-12-10
    • 1970-01-01
    • 1970-01-01
    • 2014-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多