2012-02-08 39 views
8

Tengo una consulta compleja que cruza 7 tablas y quiero saber cómo implementarlo dentro de Hibernate.Hibernate - Consulta compleja de varias tablas a un objeto

Mi intento actual es hacer la consulta usando session.createSQLQuery y yo asignaría el resultado a una entidad en particular.

No estoy seguro de cómo hacer eso, ya que en el pasado solo he trabajado con una tabla en una entidad. ¿Dónde debería especificar que me gustaría utilizar una consulta compleja que pueda abarcar varias tablas? ¿Eso solo va en mi código? Mi archivo hbm.xml? No puedo pensar en nada más allá de mi intento actual.

Aquí es un ejemplo de mi consulta:

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"; 
+0

Consulte http://stackoverflow.com/questions/21374550/fetching-data-from-multiple-tables-in-hibernate-and-storing-the-result-in-a-bean/21379254 # 21379254 – Touchstone

Respuesta

5

No es necesario SQL para ejecutar esta consulta. HQL va a estar bien. Y tal consulta devuelve un List<Object[]>, cada Object[] que contiene una fila del conjunto de resultados. Por lo tanto, encontrará la ID del cliente en el índice 0, la tarjeta en el índice 1, etc. Solo tiene que pasar por las filas y crear una instancia de su objeto liviano en cada iteración.

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

+1

en lugar de iterar la Lista y crear manualmente su objeto liviano puede usar 'seleccionar nuevo my.package.myLightWeightObject (t1.field1, t2.field2, t3.field3)' y simplemente configurar el constructor para myLightWeightObject para tomar el campos apropiados De esta forma, Hibernate devolverá una Lista en lugar de List por usted. – digitaljoel

+0

JB Nizet, sí, lo sé, pero si uso List y en el futuro, otra persona agrega un campo nuevo entre los campos actuales, ya no funciona. Me gusta la idea digitaljoel, pero no entiendo cómo hacerlo. ¿Puedes explicar un poco más? –

+0

Sí. Si cambia las tablas de la base de datos sin cambiar el código, tampoco funcionará. Implemente pruebas unitarias y verifique que la consulta funcione como se espera en las pruebas unitarias. No sé cómo puedo (o digitaljoel) ser más claro que eso. ¿Qué no entiendes? ¿Al menos has intentado algo? –

0

Así que por lo que yo puedo ver que esto es una unión de 7 mesas. Si está utilizando Hibernate, debe asignar cada una de estas tablas a entidades y luego usar @JoinColumn para asignarlas a cada una de sus dependencias. Este es el tipo de consulta SQL que hibernate está ahí para evitar que ocurra.

+0

pero tengo campos de Conteo y Suma, –

+0

Entonces solo tendrías getTotalChargePoints() como método: esa sería tu lógica comercial. De esta forma, cualquier cosa que necesite la suma o conteo individual o lo que sea, no necesita llamar a esta consulta cada vez. Para el conteo, literalmente, simplemente haría List.size() en cualquier colección de elementos con los que se una (para una relación uno a muchos) –

3

fin pude resuelto utilizando este código:

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

Sólo he añadido el "como" parte en Seleccionar y el addScalar + setResultTransformer

+0

Un problema en este enfoque es una vez si recibe los datos como tipos primitivos y si desea escribir estos datos en otra tabla que se crea con un esquema de tipos definidos por el usuario va a crear un problema. – rakeeee

4

Sus son dos maneras de hacer esto.

1. Obtendrá una matriz de objetos de lista.

List<Object[]> 

Aquí un elemento de la matriz representa una fila de su consulta.

2. Se puede utilizar una característica de hibernación ResultTransformer - Crear una clase simple para la salida de la consulta. - Crea un ResultTransformer.

Ej.

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

- configure el transformador a la consulta.

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