【问题标题】:Hibernate - Complex Query from multiple Tables to one objectHibernate - 从多个表到一个对象的复杂查询
【发布时间】:2012-03-01 03:38:06
【问题描述】:

我有一个跨越 7 个表的复杂查询,想知道如何在 Hibernate 中实现它。

我目前的尝试是使用 session.createSQLQuery 进行查询,并将结果映射到特定实体。

我不知道该怎么做,因为过去我只使用一个表到一个实体。我需要在哪里指定我想使用可以跨越多个表的复杂查询?那只在我的代码中吗?我的 hbm.xml 文件?除了我目前的尝试之外,我想不出其他任何东西。

这是我的查询示例:

String stringQuery = 
        "select  WI.Customer_Id, CU.Card, CU.Code, "+
                "PI.Identity_Card, PI.Name, PI.Surname, PI.Gender, "+
                "AD.Zip, AD.Geo_Lat, AD.Geo_Long, "+
                "CO.City_Geo_Level, "+
                "CU.Address_id, CA.Name, "+
                "CU.Category_Id, "+
                "CU.Status, "+
                "Sum(MO.Charged_Points) as Charged_Points, "+
                "Sum(MO.Total_Money) as Total_Money, "+
                "Count(MO.id) as AmountTransWinner "+
        "from Promotions_Winner WI "+ 
        "join Customers CU "+
          "on WI.Customer_id = CU.id "+
        "join Personal_Info PI "+
          "on CU.Personal_Info_Id = PI.id "+
        "join Address AD "+
          "on CU.Address_Id = AD.id "+
        "join Countries CO "+
          "on AD.country_id = CO.id "+
        "join Campaigns CA "+
          "on CU.Campaign_Id = CA.id "+
        "join Movements MO "+
          "on WI.Movement_Id = MO.id "+
        "where WI.Promotion_Id = :pPromotionID "+
        "group by "+
          "WI.Customer_Id, CU.Card, CU.Fidely_Code, "+
          "PI.Identity_Card, PI.Name, PI.Surname, PI.Gender, "+
          "AD.Zip, AD.Geo_Lat, AD.Geo_Long, "+
          "CO.City_Geo_Level, "+
          "CU.Address_id, CA.Name, "+
          "CU.Category_Id, "+
          "CU.Status";

【问题讨论】:

标签: java sql hibernate


【解决方案1】:

您不需要 SQL 来执行此查询。 HQL 会做得很好。而这样的查询返回一个List<Object[]>,每个Object[] 包含一行结果集。因此,您将在索引 0 处找到客户 ID,在索引 1 处找到卡片等。您只需遍历行并在每次迭代时创建轻量级对象的实例。

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#queryhql-select

【讨论】:

  • 而不是迭代 List 并手动创建轻量级对象,您可以使用 select new my.package.myLightWeightObject(t1.field1, t2.field2, t3.field3) 并设置 myLightWeightObject 的构造函数以获取适当的字段。这样,Hibernate 将为您返回 List 而不是 List
  • JB Nizet,是的,我知道,但是如果我使用 List 并且将来,其他人在当前字段之间添加一个新字段,它就不再起作用了。我喜欢digitaljoel的想法,但我不明白如何去做。你能再解释一下吗?
  • 是的。如果他在不更改代码的情况下更改数据库表,它也不会起作用。实施单元测试,并检查查询在单元测试中是否按预期工作。我不知道我(或digitaljoel)怎么能比这更清楚。你不明白什么?你至少尝试过什么吗?
  • 我不明白 select new my.package.myLightWeightObject(t1.field1, t2.field2, t3.field3) 去哪里了
  • 在查询的开头。你为什么不阅读文档?我给了你链接,它有一个例子。您甚至无需滚动即可找到它。
【解决方案2】:

据我所知,这是 7 个表的连接。如果您使用的是休眠,您会将这些表中的每一个映射到实体,然后使用 @JoinColumn 映射到它的每个依赖项。这是hibernate用来防止发生的那种SQL查询。

【讨论】:

  • 但我有 Count 和 Sum 字段,
  • 那么您只需将 getTotalChargePoints() 作为方法 - 这将是您的业务逻辑。这样,无论什么东西都需要单独的总和或计数,或者不需要每次都调用这个查询。对于计数,您实际上只需对它加入的任何项目集合执行 List.size() (对于一对多关系)
【解决方案3】:

我终于可以用这段代码解决了:

String stringQuery = 
                "select " +
                        "CU.Card as card, " +
                        "CU.Fidely_Code as fidelyCode, "+
                        "PI.Identity_Card as identityCard, " +
                        "PI.Name as name, " +
                        "PI.Surname as surname, " +
                        "PI.Gender as gender, "+
                        "AD.Zip as zip, " +
                        "AD.Geo_Lat as geo_lat, " +
                        "AD.Geo_Long as geo_long, "+
                        "CO.City_Geo_Level as cityGeoLevel, "+
                        "CA.Name as campaignName, "+
                        "CU.Status as status, "+
                        "Sum(MO.Charged_Points) as pointsCharged, "+
                        "Sum(MO.Total_Money) as amountPurchase, "+
                        "Count(MO.id) as amountTransWinner "+
                "from Promotions_Winner WI "+ 
                "join Customers CU "+
                  "on WI.Customer_id = CU.id "+
                "join Personal_Info PI "+
                  "on CU.Personal_Info_Id = PI.id "+
                "join Address AD "+
                  "on CU.Address_Id = AD.id "+
                "join Countries CO "+
                  "on AD.country_id = CO.id "+
                "join Campaigns CA "+
                  "on CU.Campaign_Id = CA.id "+
                "join Movements MO "+
                  "on WI.Movement_Id = MO.id "+
                "where WI.Promotion_Id = :pPromotionID "+
                "group by "+
                  "WI.Customer_Id, CU.Card, CU.Fidely_Code, "+
                  "PI.Identity_Card, PI.Name, PI.Surname, PI.Gender, "+
                  "AD.Zip, AD.Geo_Lat, AD.Geo_Long, "+
                  "CO.City_Geo_Level, "+
                  "CU.Address_id, CA.Name, "+
                  "CU.Category_Id, "+
                  "CU.Status ";

        //Query query = this.getSession().createSQLQuery(stringQuery).addEntity("", PromotionsWinnerLittle.class);
        //Query query = this.getSession().createSQLQuery(stringQuery).setResultSetMapping("PromotionsWinnerLittle");
        Query query = this.getSession().createSQLQuery(stringQuery)
            .addScalar("card", StandardBasicTypes.LONG)
            .addScalar("fidelyCode", StandardBasicTypes.LONG)
            .addScalar("identityCard", StandardBasicTypes.STRING)
            .addScalar("name", StandardBasicTypes.STRING)
            .addScalar("surname", StandardBasicTypes.STRING)
            .addScalar("gender", StandardBasicTypes.STRING)
            .addScalar("zip", StandardBasicTypes.STRING)
            .addScalar("geo_lat", StandardBasicTypes.BIG_DECIMAL)
            .addScalar("geo_long", StandardBasicTypes.BIG_DECIMAL)
            .addScalar("cityGeoLevel", StandardBasicTypes.LONG)
            .addScalar("campaignName", StandardBasicTypes.STRING)
            .addScalar("status", StandardBasicTypes.LONG)
            .addScalar("pointsCharged", StandardBasicTypes.BIG_DECIMAL)
            .addScalar("amountPurchase", StandardBasicTypes.LONG)
            .addScalar("amountTransWinner", StandardBasicTypes.LONG)            
            .setResultTransformer(Transformers.aliasToBean(PromotionsWinnerLittle.class));

        //Query query = this.getSession().createSQLQuery(stringQuery);

        query = query.setLong("pPromotionID", promotionID);

        List lista = query.list();

我刚刚在 Select 和 addScalar + setResultTransformer 上添加了“As”部分

【讨论】:

  • 这种方法的一个问题是,如果您将数据作为原始类型接收,并且如果您想将此数据写入另一个使用用户定义类型的模式创建的表,则会产生问题。
【解决方案4】:

他们有两种方法可以做到这一点。

1.你会得到一个列表对象数组。

 List<Object[]>

这里数组的一个元素代表你的查询的一行。

2.您可以使用休眠功能ResultTransformer - 为查询的输出创建一个简单的类。 - 创建一个 ResultTransformer。

例如

 public class MyResultTransformer implements ResultTransformer {


/*
Method to convert to generic type list
*/
    @Override
    public List<Employee> transformList(List arg0) {
        List<Employee> employees = new ArrayList<Employee>();
        for (Object employee : arg0) {
            employees.add((Employee) employee);
        }
        return employees;
    }

    /*
    Code to transform your query output to Object
    */
    @Override
    public Employee transformTuple(Object[] arg0, String[] arg1) {
        System.out.println("MyResultTransformer.transformTuple()");
        Employee tempEmp = new Employee();
        tempEmp.setEmployee_id((BigInteger) arg0[0]);
        return tempEmp;
    }
}

- 为查询设置转换器。

Query query=session.createSQLQuery("SELECT * FROM employeedetail"); // You can use named query, SQL native also
      query.setResultTransformer(new MyResultTransformer());
          List<Employee> employees=query.list();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 2018-11-09
    • 1970-01-01
    • 2013-12-31
    相关资源
    最近更新 更多