-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 
Author Message
 Post subject: Anderthalb Criteria Queries (max)
PostPosted: Mon Aug 29, 2005 6:11 am 
Beginner
Beginner

Joined: Thu Apr 14, 2005 4:29 am
Posts: 28
Hallo,

ich sitze nun schon eine Weile über paar Criteria Queries und würde mich über etwas Hilfe da freuen.

Ich habe zwei einfache (verknüpfte) Tabellen:
- ProductCategory mit den Spalten id, name (z.B. Lebensmittel) und last_update (hält das Erstellungsdatum der Produktkategorie fest).
- Item mit den Spalten id, name (z.B. Butter), category (Verweis auf Produktkategorie) und last_update (Erstellungs bzw. Änderungsdatum des Produktes).

Nun möchte ich zwei Abfragen machen:
a) Ich möchte gerne die zuletzt hinzugefügte Produktkategorie wissen.
session.createCriteria(ProductCategory.class)
.setProjection(Projections.max("last_update"))
.list();
Das funktioniert auch, nur liefert er mir hier nur das Datum der zuletzt hinzugefügten Produktgruppe und nicht diese selbst zurück. Wie müsste ich die Anfrage dementsprechend ändern?

b)
Ich möchte folgendes Ergebnis haben: Liste mit Produktgruppe und das jeweils zuletzt hinzugefügte bzw. bearbeitete Produkt dafür?

Grüsse und vielen Dank
Detlev


Hibernate version: 3.0.5


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 29, 2005 6:33 am 
Regular
Regular

Joined: Sun Aug 01, 2004 6:49 pm
Posts: 76
Mmmhhh, habe noch nichts mit Projections gemacht, aber wie wäre es mit einem einfachen Order in Verbindung mit Maxresults:

Code:
session.createCriteria(ProductCategory.class)
.addOrder(Order.asc("last_update"))
.setMaxResults(1)
.list();


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 29, 2005 6:38 am 
Regular
Regular

Joined: Sun Aug 01, 2004 6:49 pm
Posts: 76
Ich vergaß zu b). Hier mußt Du eine one-to-many Verknüpfung in ProductCategory schaffen, die als SortedSet mit order-by oder sort nach last_update sortiert ist. Dein aktuellstes Prdoukt ist dann immer das erste Element dieses Sets.

HTH
Thomas


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 29, 2005 6:58 am 
Beginner
Beginner

Joined: Thu Apr 14, 2005 4:29 am
Posts: 28
Danke für deine Antowrt.

addOrder und setMaxResult sind nicht falsch aber bewirken doch in diesem Zusammenhang rein gar nichts. Wieso sortieren wenn man nur eine List mit einem Objekt zurück bekommt?

Bei a) habe ich doch schon das richtige Ergebnis (Liste mit einem Objekt) aber halt nur das Datum und nicht die Produktgruppe selbst.

Bei b) ist die ProductCategory bereits über eine one-to-many Verknüpfung items mit der Tabelle bzw . Klasse Item verknüpft. Das vergass ich zu erwähnen, das ist sicher die Grundvoraussetzung. Ein order-by nützt doch nichts wenn ich erstmal die Ergbnismenge einschränken muss. Ich möchte doch nicht die Ergbnismenge sortieren maximal hier nach Kategorienamen aber das ist ja nicht das Problem.

Grüsse
Detlev


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 29, 2005 7:08 am 
Regular
Regular

Joined: Sun Aug 01, 2004 6:49 pm
Posts: 76
Sorry, aber Deine Verständnis von SQL ist nicht vollständig. Wenn Du eine Aggregatfunktion benutzt ("max") dann heißt das nicht zwangsläufig daß die restlichen Rückgabefelder auch zu dem Objekt passen, bzw. genau das Objekt sind, das das Maximum enthält. Probier das mal direkt mit SQL-Queries. Deshalb wird Dir eben auch nur das qualifizierte Ergebnis - das maximale Datum zurückgegeben.

Genau das gleiche Problem hast du mit b). Auch hier hilft nur die Sortierung und wieder das entsprechende 1. Objekt aus der Liste.

HTH
Thomas


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 29, 2005 5:29 pm 
Beginner
Beginner

Joined: Thu Apr 14, 2005 4:29 am
Posts: 28
Guten Abend,

so langsam bin ich am Verzweifeln mit der Criteria API und Subqueries. Mit HQL habe ich die selben Abfragen hinbekommen. Ich möchte aber gerne die Criteria API nehmen weil man damit leichter und übersichtlicher komplexe Suchabfragen gestalten kann. Nachfolgend ist ein stark vereinfachtes Beispiel welches vielleicht nicht ganz sinnvoll ist aber gut das Problem zeigt.

Probleme bereiten mir die Abfragen B (wie komme ich an die Item Objekte) und C.

Nachfolgend der komplette Code, vielleicht findet ja jemand eine ganz einfache Criteria Abfrage und ich habe Tomaten auf den Augen.

Grüsse
Detlev

Code:
package eg;

import java.util.*;

import org.hibernate.*;
import org.hibernate.cfg.*;
import org.hibernate.criterion.*;

public class ProductMain
{
  private SessionFactory sessionFactory;
  private Session session;

  public void configure() throws HibernateException
  {
    sessionFactory = new Configuration()
                            .addClass(ProductCategory.class)
                            .addClass(Item.class)
                            .buildSessionFactory();
    session = sessionFactory.openSession();
  }
 
  /**
   * lists all product categories and their product items
   */
  private void testAll()
  {
    System.out.println("\nTEST All categories with items.");
    List list = session.createCriteria(ProductCategory.class)
                         .list();
    for (int i = 0; i < list.size(); i++)
    {
      ProductCategory procat = (ProductCategory) list.get(i);
      System.out.println(procat.getName() + " (" + procat.getId() + ")" +  ", last update: " + procat.getLastUpdate());
      List items = procat.getItems();
      for (Iterator iter = items.iterator(); iter.hasNext();)
      {
        Item element = (Item) iter.next();
        System.out.println("==> " + element.getName() + " (" + element.getId() + "), discount: "
                          + element.getDiscount() + ", last update: " + element.getLastUpdate());
      }
    }
  }
 
  /**
   * Result should be the name of the last edited product category
   */
  private void testA()
  {
    //  .uniqueResult(); not sure if more than one row
   
    System.out.println("\nTest A");
   
    System.out.println("\n  First solution");
    List list1 = session.createCriteria(ProductCategory.class)
                                .addOrder(Order.desc("lastUpdate"))
                                .setMaxResults(1)
                                .list();
    ProductCategory pc1 = (ProductCategory) list1.get(0);
    System.out.println("Category: " + pc1.getName() + ", " + pc1.getLastUpdate());
   
    System.out.println("\n  Second solution");
    DetachedCriteria dc2 = DetachedCriteria.forClass(ProductCategory.class)
                                            .setProjection(Property.forName("lastUpdate").max());
    ProductCategory pc2 = (ProductCategory) session.createCriteria(ProductCategory.class)
                                       .add(Property.forName("lastUpdate").eq(dc2))
                                       .uniqueResult();
    System.out.println("Category: " + pc2.getName() + ", " + pc2.getLastUpdate());

    System.out.println("\n  Third solution");
    DetachedCriteria dc3 = DetachedCriteria.forClass(ProductCategory.class)
                                           .setProjection(Projections.max("lastUpdate"));
    ProductCategory pc3 = (ProductCategory) session.createCriteria(ProductCategory.class)
                                   .add(Subqueries.propertyEq("lastUpdate", dc3))
                                   .uniqueResult();
    System.out.println("Category: " + pc3.getName() + ", " + pc3.getLastUpdate());
  }
 
  /**
   * Result should be a list with product categories and the last added item to this category
   *
   * For instance:
   * Food ==> Juice (4), discount: 30, last update: 2005-08-27 00:00:00.0
   * Car ==> Ugly car (7), discount: 40, last update: 2005-08-28 00:00:00.0
   */
  private void testB()
  {
    System.out.println("\nTest B");

    // next one trial of many
    List list = session.createCriteria(Item.class)
                       .setProjection(Projections.projectionList()                             
                                .add(Projections.max("lastUpdate"))
                                .add(Projections.groupProperty("category")))
                       .list(); 
    System.out.println("size: " + list.size());
   
    for (Iterator iter = list.iterator(); iter.hasNext();)
    {
      Object element = (Object) iter.next();
      Object[] array = (Object[]) element;
      Object o = array[0];
      ProductCategory pc = (ProductCategory) array[1]; 
      System.out.println("Cat: " + pc.getName() + ", " + o);
    } 
  }
 

  /**
   * Result should be a list with product categories and the last added item to this category
   * which has the given discount
   *
   * For instance (discount=10):
   * Food ==> Butter (3), discount: 10, last update: 2005-08-22 00:00:00.0
   *
   * @param discount
   */
  private void testC(int discount)
  {
    System.out.println("\nTest C");
    // like Test C but additional with discount = 10
  }
 
  public static void main(String[] args)
  {
    ProductMain m = new ProductMain();
    m.configure();
    m.testAll();
    m.testA();
    m.testB();
    m.testC(10);
  }
}


Code:
package eg;

import java.sql.*;
import java.util.*;

public class ProductCategory
{
  private Long id;
  private String name;
  private Timestamp lastUpdate;
  private List items;
 
  public Long getId()
  {
    return id;
  }
  public void setId(Long id)
  {
    this.id = id;
  }
  public Timestamp getLastUpdate()
  {
    return lastUpdate;
  }
  public void setLastUpdate(Timestamp lastUpdate)
  {
    this.lastUpdate = lastUpdate;
  }
  public String getName()
  {
    return name;
  }
  public void setName(String name)
  {
    this.name = name;
  }
  public List getItems()
  {
    return items;
  }
  public void setItems(List items)
  {
    this.items = items;
  }
}


Code:
package eg;

import java.sql.*;

public class Item
{
  private long id;
  private String name;
  private int discount;
  private ProductCategory category;
  private Timestamp lastUpdate;
 
  public ProductCategory getCategory()
  {
    return category;
  }
  public void setCategory(ProductCategory category)
  {
    this.category = category;
  }
  public int getDiscount()
  {
    return discount;
  }
  public void setDiscount(int discount)
  {
    this.discount = discount;
  }
  public long getId()
  {
    return id;
  }
  public void setId(long id)
  {
    this.id = id;
  }
  public Timestamp getLastUpdate()
  {
    return lastUpdate;
  }
  public void setLastUpdate(Timestamp lastUpdate)
  {
    this.lastUpdate = lastUpdate;
  }
  public String getName()
  {
    return name;
  }
  public void setName(String name)
  {
    this.name = name;
  }
}


Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="eg">
   <class name="ProductCategory" table="productcategory" lazy="true">
      <id name="id" column="id">
         <generator class="increment"/>
      </id>
      <property name="name" column="name" not-null="true" unique="true"/>
      <property name="lastUpdate" column="last_update" />
      <bag name="items" inverse="true" lazy="true" cascade="all">
         <key column="category"/>
         <one-to-many class="Item"/>
      </bag>
   </class>
</hibernate-mapping>


Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="eg">
   <class name="Item" table="item" dynamic-update="true">
      <id name="id" column="id">
         <generator class="increment"/>
      </id>   
      <property name="name" column="name" not-null="true"/>
      <property name="discount" column="discount" not-null="true"/>
      <property name="lastUpdate" column="last_update" type="timestamp"/>
      <many-to-one name="category" column="category" not-null="true"/>
   </class>
</hibernate-mapping>


Code:
CREATE TABLE productcategory (
       id INT NOT NULL
     , name VARCHAR(50) NOT NULL
     , last_update TIMESTAMP NOT NULL
     , PRIMARY KEY (id)
);

CREATE TABLE item (
       id INT NOT NULL
     , name VARCHAR(50) NOT NULL
     , discount INT NOT NULL
     , category INT NOT NULL
     , last_update TIMESTAMP NOT NULL
     , PRIMARY KEY (id)
     , CONSTRAINT FK_item_1 FOREIGN KEY (category)
                  REFERENCES productcategory (id)
);


Code:
INSERT INTO productcategory(id, name, last_update) VALUES(1, 'Food', '2005-08-20');
INSERT INTO productcategory(id, name, last_update) VALUES(2, 'Car', '2005-08-21');

INSERT INTO item(id, name, discount, category, last_update) VALUES(1, 'Bread', 10, 1, '2005-08-20');
INSERT INTO item(id, name, discount, category, last_update) VALUES(2, 'Chocolate', 30, 1, '2005-08-25');
INSERT INTO item(id, name, discount, category, last_update) VALUES(3, 'Butter', 10, 1, '2005-08-22');
INSERT INTO item(id, name, discount, category, last_update) VALUES(4, 'Juice', 30, 1, '2005-08-27');

INSERT INTO item(id, name, discount, category, last_update) VALUES(5, 'Nice car', 30, 2, '2005-08-21');
INSERT INTO item(id, name, discount, category, last_update) VALUES(6, 'Beautiful car', 25, 2, '2005-08-22');
INSERT INTO item(id, name, discount, category, last_update) VALUES(7, 'Ugly car', 40, 2, '2005-08-28');
INSERT INTO item(id, name, discount, category, last_update) VALUES(8, 'Yellow car', 30, 2, '2005-08-26');


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 29, 2005 5:39 pm 
Regular
Regular

Joined: Sun Aug 01, 2004 6:49 pm
Posts: 76
Ich will ja nicht nerven., aber mache Deine Items zu Set und sortiere das Teil nach last_update. Dann haste alles was Du brauchst. Jetzt bin ich aber ruhig.

Gutes Nächtle
Thomas


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 30, 2005 1:19 am 
Beginner
Beginner

Joined: Thu Apr 14, 2005 4:29 am
Posts: 28
Hallo,

nein, du nervtst nicht, bin dankbar für deine Hilfe.

Nur bin ich nicht in der Lage, sie gewinnbringend einzusetzen. Wenn Du mal Muse bzw. Zeit hast und das Beispiel von mir ausprobierst wäre ich sehr dankbar. Die zu erwartenden Ergebnisse stehen bei Methode b und c.
So einfach ist das meines Erachtens nicht mit der Criteria API wie ich bei meinen Versuchen herausbekam.
Dein Vorschlag des Sortierens und dann den letzten bzw. ersten Wert zu nehmen, funktioniert hier in meinem simplen Fall zumindest bei Test A.
Es kann aber auch ähnliche Fälle geben wie den Durchschnitt von Werten wo man damit nicht weiter kommt und auf die Aggregatfunktion avg und die entsprechenden Möglichkeiten in der Criteria API mit Restrictions (evtl. DetachedQueries, Subqueries) angewiesen ist.

Lange Rede kurzer Sinn, ich bekomme die Abfragen für b und C immer noch nicht hin.

Grüsse
Detlev

PS:
bei c) sollte mich dann die sortierte Liste auch nicht weiterbringen oder?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 31, 2005 12:07 pm 
Regular
Regular

Joined: Sun Aug 01, 2004 6:49 pm
Posts: 76
Detlev, ich bin ja sehr geduldig, aber leider habe ich nicht die Zeit Deine Tests zu fahren. Bitte, bitte, bitte probiere es so wie ich es gesagt habe.
Mache Deine Items zu einem sortierten Set, wenn Du nicht weisst wie es geht schaue bitte erst in der Dokumentation nach und wenn das dann noch unklar ist melde Dich nochmal. Das löst B) auf jeden Fall.
Ich verstehe einfach nicht was Du mit den Aggregaten wie AVG usw. willst. Du kannst nun mal nicht die eierlegende Wollmilchsau mit einem Query haben.

Auch zu C) gibt es eine Anleitung in der Doku mit Cats und Kittens, wenn mich nicht alles täuscht: http://www.hibernate.org/hib_docs/v3/re ... sociations
Das Mapping dazu ist das gleiche wie B) nur daß der Query etwas spezieller ist.

Gruß
Thomas


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.