모든 개발자는 Order생성, OrderItems가 되는 것에 Products를 넣고 Order를 저장하는 것과 같은 작업을 최소한 한번을 수행한다. 우리는 우리의 DB를 셋업하기 위한 다음과 같은 간단한 SQL문을 사용할 것이다.

CREATE TABLE ORDERS(
        ID VARCHAR NOT NULL PRIMARY KEY,
        ORDER_DATE TIMESTAMP NOT NULL,
        PRICE_TOTAL DOUBLE NOT NULL)

CREATE TABLE PRODUCTS(
        ID VARCHAR NOT NULL PRIMARY KEY,
        NAME VARCHAR NOT NULL,
        PRICE DOUBLE NOT NULL,
        AMOUNT INTEGER NOT NULL)

CREATE TABLE ORDER_ITEMS(
        ID VARCHAR NOT NULL PRIMARY KEY,
        ORDER_ID VARCHAR NOT NULL,
        PRODUCT_ID VARCHAR NOT NULL,
        AMOUNT INTEGER NOT NULL,
        PRICE DOUBLE NOT NULL)

이 데이터모델은 좀더 단순하다. 사실 "production quality"데이터 모델은 foreign keys, index들, 추가적인 필드들 또는 기타등등이 필요하다. 하지만 이 튜토리얼을 위해서는 위 데이터모델로도 충분하다.

Java Code#

비지니스 요구사항이 간단하고 이해하기 쉬운것일지라도 prepared statement를 사용하는 기존의 방식은 빨리 지루해진다. 하이버네이트를 이런것들로 부터 우리를 자유롭게 한다. 단지 우리가 필요한것은 간단한 맵핑파일들이다. 그러나 먼저 우리는 우리의 자바클래스들을 생성할 필요가 있다.

Product

이 간단한 클래스는 단지 ID, 제품이름, 제품가격, stock에 필요한 아이템의 최근의 물량이라는 필요한 필드만 정의한다. 하이버네이트를 명백하고 간단한 자바빈즈로 작동되기 때문에 우리는 모든 명백한 필드를 위한 getter와 setter메소드와 디폴트 생성자가 필요하다.

package test.hibernate;

public class Product {
    private String id;
    private String name;
    private double price;
    private int amount;
    
    public String getId() {
        return id;
    }
    public void setId(String string) {
        id = string;
    }
    // default constructor and other 
    // getters/setters not shown for brevity
    // ...
}

우리는 toString()메소드를 오버라이딩했다. 이는 다음처럼 간단한 System.out.println(obj)를 사용할때 좀더 우리를 도와준다.

public String toString() {
    return 
     "[Product] " + name + "(" + id +
     ") price=" + price + " amount=" + amount;
}

이것이 다다. 더 할것도 덜 할것도 없다. 그럼 Product는 어떤 인터페이스도 어떤 확장 클래스도 구현하지 않았는데, 하이버네이트는 이 타입의 객체를 어떻게 알아낼까.? 답은 간단하다. 하이버네이트는 다음의 자바빈즈의 규칙이 존재하는한 어떤 종류의 자바객체와 수행될것이다.

Order

우리가 생성할 필요가 있는 다음 클래스는 Order이다. 이것은 Product보다 더 간단하다. 단지 ID, 생성날짜, 총가격, Order를 구성하는 OrderItems의 집합을 포함할 뿐이다. 물론 getter와 setter, 그리고 디폴트 생성자는 생성해야 한다.

package test.hibernate;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

 public class Order {
    private String id;
    private Date date;
    private double priceTotal;
    private Set orderItems = new HashSet();
    
    // Automatically set the creation time of 
    // this Order
    public Order() {
        this.date = new Date();
    }

    public String getId() {
        return id;
    }
    public void setId(String string) {
        id = string;
    }
    // other getters/setters not shown for 
    // brevity
    // ...
}

OrderItem

이 클래스는 약간 복잡하다. 그러나 아직도 실제론 간단하다. 우리의 비지니스 요구는 Order에 넣을 Product의 어느정도의 량이 필요하다고 말한다. 그 Product들은 자동적으로 OrderItems가 될것이다. 이것은 custom생성자에서 수행된다.

package test.hibernate;

public class OrderItem {

    /**
    * Creates valid OrderItem. Automatically sets 
    * this OrderItem's price and corrects 
    * Product's stock availability amount.
    
    @param order to which this OrderItem belongs
    @param product from which this OrderItem is created
    @param amount 
    */
    public OrderItem(Order order, 
                     Product product, 
                     int amount) {
                     
        this.order = order;
        this.product = product;
        this.amount = amount;
        product.setAmount(product.getAmount() - amount);
        this.price = product.getPrice() * amount;        
    }

    // we also need default constructor to keep
    // Hibernate happy
    /**
    * Empty constructor to conform to JavaBeans 
    * convention.
    *
    */
    public OrderItem() {
        // empty default constructor
    }

    // fields
    private String id;
    private Product product;
    private Order order;
    private String productId;
    private String orderId;
    private double price;
    private int amount;
    
    public String getId() {
        return id;
    }
    public String getProductId() {
        return product.getId();
    }
    public String getOrderId() {
        return order.getId();
    }
    // other getters/setters not shown
    // ...

    // convenient way to display this OrderItem
    public String toString() {
        return 
          "[OrderItem] id=" + id + " amount=" 
          amount + " price=" + price + "(" 
          product + ")";
    }
}

이제 우리는 DB구조를 반영하는 모든 클래스를 가지고 있다. 단지 Products를 Order로 어떻게 넣을지에 대한 것만 남기고 있다. 이것은 Order클래스에 다음과 같은 메소드를 추가하면 간단하다.

/**
* Add a Product to this Order. Product 
* automatically becomes an OrderItem.
* The priceTotal is automatically updated.

@param p Product to add to this Order
@param amount amount of products to add
*/
public void addProduct(Product p, 
                       int amount) {

   OrderItem orderItem = new OrderItem(this, 
                         p, amount);
                         
   this.priceTotal = this.priceTotal 
                     + p.getPrice() * amount;
                     
   this.orderItems.add(orderItem);
}

Starting Up Hibernate#

우리의 가상의 어플리케이션의 기본적인 사용패턴은 간단하다. 우리는 Product를 생성하고 저장할것이다. 우리는 이미저장된 Product를 찾거나 다시 부를것이고 이는 매우 유용하게 한다. 그리고 우리는 Product를 수정하거나 삭제할것이다.

Create And Persist A Product

마침내 우리는 하이버네이트를 사용한다. 사용시나리오는 비교적 간단하다.

  1. . 유효한 Product를 생성
  2. . 어플리케이션을 시작할때 net.sf.hibernate.cfg.Configuration를 사용하는 net.sf.hibernate.SessionFactory를 얻어온다.
  3. . SessionFactory.openSession()메소드를 호출함으로써 net.sf.hibernate.Session을 연다.
  4. . Product를 저장하고 Session을 닫는다.

보는것처럼 여기엔 JDBC, SQL 또는 다른 유사한 것들에 대한 언급이 없다. 다음의 샘플이 위에서 언급된 과정을 그대로 따라간다.

package test;

import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.cfg.Configuration;
import test.hibernate.Product;

// use as
// java test.InsertProduct name amount price
public class InsertProduct {

    public static void main(String[] args
                        throws Exception {

        // 1. Build a Product
        Product p = new Product();
        p.setName(args[0]);
        p.setAmount(Integer.parseInt(args[1]));
        p.setPrice(Double.parseDouble(args[2]));

        // 2. Fire up Hibernate
        Configuration cfg = new Configuration()
                         .addClass(Product.class);
        SessionFactory sf = cfg.buildSessionFactory();

        // 3. Open Session
        Session sess = sf.openSession();

        // 4. Save Product and close Session
        Transaction t = sess.beginTransaction();
        sess.save(p);
        t.commit();
        sess.close();
    }
}

첫수행을 위해 이를 실행시키자. test.InsertProduct Milk 100 1.99를 이슈화함으로써 1.99의 우유 100병을 추가해 보자. 우리는 다음과 같은 것을 보게 될것이다.

Nov 23, 2003 9:05:50 AM net.sf.hibernate.cfg.Environment <clinit> INFO: Hibernate 2.0.3 Nov 23, 2003 9:05:50 AM net.sf.hibernate.cfg.Environment <clinit> INFO: hibernate.properties not found

Nov 23, 2003 9:05:50 AM net.sf.hibernate.cfg.Environment <clinit> INFO: using CGLIB reflection optimizer Nov 23, 2003 9:05:50 AM net.sf.hibernate.cfg.Environment <clinit> INFO: JVM proxy support: true Nov 23, 2003 9:05:50 AM net.sf.hibernate.cfg.Configuration addClass INFO: Mapping resource: test/hibernate/Product.hbm.xml Exception in thread "main" net.sf.hibernate.MappingException: Resource: test/hibernate/Product.hbm.xml not found at net.sf.hibernate.cfg.Configuration.addClass(Configuration.java:285) at test.FindProductByName.main(FindProductByName.java:24)

제대로 수행되지 않았다. 특별히 두 라인에 흥미를 가질수 있다.

INFO: hibernate.properties not found and

Resource: test/hibernate/Product.hbm.xml not found.

INFO라인은 hibernate.properties설정파일의 필요성을 표시한다. 물론 그것은 우리가 DB를 사용하기 위한 설정(유저명, 비밀번호, 다른 많은 옵션들)을 담아두는 파일이다. 전에 언급된 Hypersonic DB에 연결하기 위한 샘플을 사용한다.

hibernate.connection.username=sa
hibernate.connection.password=
hibernate.connection.url=jdbc:hsqldb:/home/davor/hibernate/orders
hibernate.connection.driver_class=org.hsqldb.jdbcDriver
hibernate.dialect=net.sf.hibernate.dialect.HSQLDialect
hibernate.connection.url같은 것을 변경하고 당신의 classpath에 저장해라.

이것은 쉬운것이다. 그러나 test/hibernate/Product.hbm.xml는 무엇인가..? 이것은 자바객체와 DB와의 매핑을 어떻게 할것인지 정의하는 xml파일이다. 이 파일에 데이터가 들어가는 DB테이블과 어떤 필드가 어떤 테이블 column에 매핑되는지, 다른 객체가 서로 어떻게 연결되는지 등등을 정의한다. 그럼 Product.hbm.xml파일을 살펴보자.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
    
<hibernate-mapping>
    <class name="test.hibernate.Product" 
           table="products">
              
        <id name="id" type="string" 
            unsaved-value="null">
            <column name="id" sql-type="char(32)" 
                    not-null="true"/>
            <generator class="uuid.hex"/>
        </id>
        <property name="name">
            <column name="name" sql-type="char(255)" 
                    not-null="true"/>
        </property>
        <property name="price">
            <column name="price" sql-type="double" 
                    not-null="true"/>
        </property>
        <property name="amount">
            <column name="amount" sql-type="integer" 
                    not-null="true"/>
        </property>        
    </class>
</hibernate-mapping>
이는 매우 간단하고 이해하기 쉽다. 몇몇 상세정보는 흥미가 간다.

  • <class name="test.hibernate.Product" table="products"> 이는 product라는 DB테이블이 test.hibernate.Product라는 이름의 클래스에 매핑된다는 것을 말한다.
  • <id> 는 원소이면서 우리의 자바클래스와 DB사이의 연결을 정의하는 하위 원소이다.
  • <property> 는 각각의 필드가 자신의 타입과 이름등등을 테이블의 어느 칼럼에 매치시킬지 정의한다.

<generator class="uuid.hex"/> 는 처음엔 분명하게 이해되지는 않는다. <id>의 하위원소중에 하나라는것을 알아두어라. 이 데이터가 어떻게 저장이 되는지 알지 못하더라도 이것의 역활은 조금씩 명백해 질것이다. 우리는 대체키가 필요하다. 비지니스 의미없이 하이버네이트는 객체를 능숙하게 다룰수 있도록 도울것이다. 새롭게 생성된 Products는 id를 가지지 않고 하이버네이트는 이것을 생성할 것이다. 우리는 UUID를 사용한다. 그러나 많은 서로 다른 ID생성자가 제공된다. 그리고 당신은 당신 자신의 ID생성자를 쓸수 있다.

지금 Product.hbm.xml의 콘텐츠를 생성하자. 그리고 test.hibernate.Product클래스와 같은 위치에 두어라. 그리고 java test.InsertProduct Milk 100 1.99를 다시 실행시켜라. 지금 우리는 더 많은 로깅정보를 보게된다. 제대로 작동을 하는가.? Session sess = sf.openSesion(); 을 하기 전에 System.out.println(p)를 추가하고, sess.close()뒤를 보아라. 다시 실행시켜보면 비슷한것을 다시 볼수 있을것이다.(아마도 ID는 분명히 다를것이다.)

Product Milk(null) price=1.99 amount=100 Product Milk(40288081f907f42900f907f448460001) price=1.99 amount=100

하이버네이트는 Product의 ID를 생성했다. Product가 DB에 저장이 되었는지 보라. 쿼리를 해보면 다음과 비슷한것을 볼수 있다.

ID |NAME |PRICE |AMOUNT | 40288081f907f42900f907f448460001|Milk |1.99 |100 |

Product정보는 성공적으로 DB에 저장이 되었고 우리는 한줄의 SQL문도 사용하지 않았다. 몇가지 다른 Products도 추가해 보라.

Find And Load Products#

이미 존재하는 객체를 찾고 다시 불러들이는 것은 하이버네이트를 사용할때라면 매우 간단하다. ID와 이름, 다른 몇몇의 속성으로 객체를 쉽게 가져오기 위한 쿼리를 사용하자. 우리는 완전한 객체를 가져올수도 몇몇 속성을 가져올수도 있다. 하이버네이트는 쉬게 할것이다. 마지막에 우리는 객체의 완전하게 유용한 구조를 가지게 될것이다. test.FindProductByName 클래스를 보자.

package test;

import java.util.List;


import net.sf.hibernate.Hibernate;
import net.sf.hibernate.Session;

import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.cfg.Configuration;
import test.hibernate.Product;

// use as 
// java test.FindProductByName name
public class FindProductByName {

    public static void main(String[] argsthrows Exception {
        // query to issue
        String query =
            "select product from product "
            "in class test.hibernate.Product "
            "where product.name=:name";

        // search for what?
        String name = args[0];

        // init
        Configuration cfg = new Configuration()
                           .addClass(Product.class);

        SessionFactory sf = cfg.buildSessionFactory();

        // open session
        Session sess = sf.openSession();
        
        // search and return
        List list = sess.find(query, name, 
                              Hibernate.STRING);

        if (list.size() == 0) {
            System.out.println("No products named " 
                               + name);
            System.exit(0);
        }
        Product p = (Productlist.get(0);
        sess.close();
        System.out.println("Found product: " + p);
    }

}

우리는 FindProductByName에서 흥미있는 것을 몇가지 볼수 있다.

  • where이라는 요소를 가지는 쿼리이다. 이것은 기본적인 SQL문과 매우 유사하다.
  • 첫 예제처럼 하이버네이트를 조기화한다. 이때 우리는 설정파일과 매핑파일을 가지고 있다.
  • sess.find()는 쿼리를 수행하고 Hibernate.STRING타입의 인자인 제품이름으로 데이터셋을 찾는다.
  • 결과처럼 우리는 java.util.List타입의 모든 데이터를 가지게 된다.
  • Product p = (Product) list.get(0); 형변환과 함께 이런 방식으로 객체를 가져온다.

java test.FindProductByName Milk 를 수행하고 콘솔을 보라.

Note: 쿼리는 대소문자를 가린다. 그래서 소문자인 milk로 찾으면 어떤 결과로 반환하지 않는다. 그로인한 실수를 막기 위해 lower()또는 upper()를 사용하라. 이런경우 우리는 쿼리에 lower(product.name)=lower(:name)이런식으로 사용한다. INFO로깅 정보를 보지 않기 위해서는 log4j.properties를 수정(모든 로깅레벨을 warn으로 맞추어라)하라.

Update And Delete Products#

지금쯤 당신은 하이버네이트 사용법에 대한 기본적인 이해를 하고 있다. 그래서 소스에서 중요한 부분만 보여줌으로서 긴 소스를 짧게 보여줄것이다.

단 하나의 트랜잭션으로 모든 Product의 가격을 10% 올리기 위해서 우리는 다음처럼 했다.

double percentage = Double.parseDouble(args[0])/100;

sess = sf.openSession();
Transaction t = sess.beginTransaction();

// list contains Products
Iterator iter = list.iterator();
while (iter.hasNext()) {
    Product p = (Productiter.next();            
    p.setPrice(p.getPrice() (+ percentage));
    sess.saveOrUpdate(p);      
}
t.commit();
sess.close();

마지막으로 Product를 삭제하기 위해서 우리는 물론 sess.delete(product)메소드를 호출할것이다. 만약에 당신의 DB의 autocommit값이 false라면 commit()를 잊지말고 해야한다.

지금 우리는 하나의 객체에 대한 기본적인 작업(create, read, update, delete)에 대해 진행했다. 흥미롭게 보인다. 하지만 더 많은 것을 얻어야 한다. 우리는 하나의 SQL문장을 사용하지 않고도 객체의 집합을 관리하는 방법을 배울것이다. 마법의 모든것은 매핑파일에 의해 이루어진다.

Orders, OrderItems

일대일의 객체를 관리하는것은 확실히 저장될것이다. 하지만 우리는 단계적으로 로드되고 수정되는것을 원한다. 지금 어떻게 하는지 보자.

우리는 동시에 Orders와 OrderItems를 시험할 필요가 있다. 전에 말했던 것처럼 우리는 Order에 Product를 추가하고 이것은 OrderItem이 될것이다. Order는 내부적으로 OrderItems의 집합으로 유지된다. 우리가 원하는것은 Order를 저장하는것이고 나머지(OrderItems저장하기, 추가된 Products의 stock유효성 수정하기)는 하이버네이트가 수행한다. 복잡하게 들지만 이것은 사실 매우 간단하다. 하이버네이트는 일대일, 일대다, 다대일 형식의 관계된 객체를 처리하는 방법을 알고있다. 우리는 매핑파일과 함께 시작할것이다.

Order.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
    <class name="test.hibernate.Order" table="orders">
        <id name="id" type="string" unsaved-value="null" >
            <column name="id" sql-type="char(32)" not-null="true"/>
            <generator class="uuid.hex"/>
        </id>
        <property name="date">
         <column name="order_date" 
                 sql-type="datetime" not-null="true"/>
        </property>
        <property name="priceTotal">
        <column name="price_total" 
                sql-type="double" not-null="true"/>
        </property>
        
        <set name="orderItems" table="order_items" inverse="true"  cascade="all">
            <key column="order_id" />
            <one-to-many class="test.hibernate.OrderItem" />
        </set>
        
    </class>
</hibernate-mapping>

매핑파일은 마지막의 <set>를 제외하고는 매우 이해하기 쉽다. 이것은 서로 다른 클래스사이의 연결을 표시한다. 우리의 경우는 Order과 OrderItem사이의 연결이다. 속성과 하위 원소는 쉽게 이해할수 있다. OrderItems라는 set타입의 필드, <one-to-many>하위 원소로 설명되는 test.hibernate.OrderItem타입의 객체를 포함한다. 이 객체들은 객체의 OrderItem타입을 위한 키를 포함하는 order_id칼럼이 있는 order_items테이블내에 존재한다.

cascade="all" 속성은 매우 중요한것이다. 이것은 연결된 객체를 다루는 동안 하이버네이트가 어떻게 작동을 해야 하는 지 설명한다. 우리의 특정환경에서는 Order이 생성되었을때, 우리는 제대로 생성된 OrderItems의 모든것을 명백하게 원하고 뿐만 아니라 Order가 삭제되었을때 우리는 삭제될 OrderItem의 모든것 또한 원한다. cascade속성을 hold, none, save-update, delete할수 있는 3개 이상의 옵션이 있다. 다음의 예제에서 우리는 그것들을 사용하는 방법에 대해서 볼것이다.

OrderItem.hbm.xml

이 객체는 흥미로운 것이다. 이것의 인스턴스는 Order내에서 자동적으로 생성이 되고, 기본적으로 이것의 외부에서 생명(life)을 가지지 않는다. 어쨌든 우리는 그것들이 필요하다. 그것들은 Order이 생성되었을때 Products를 표현한다. 그리고 만약에 Product's price이 변경되었다면 우리는 전유하는 OrderItems의 모든것을 명백히 원하지는 않고, Order's price가 변경된다. OrderItem이 생성될때마다 우리가 Product의 주가 효용성을 수정하길 원한다. 마지막에 Order이 삭제되었을때 이것의 OrderItems이 삭제된다. 하지만 Products를 건드리지 않는다. 특별히 쓰여질 SQL문의 모든것이 필요할때는 복잡하게 들릴것이다. 하지만 맵핑 파일내에 두 라인을 추가함으로써 그 모든것을 요약할수 있다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
    <class name="test.hibernate.OrderItem" 
             table="order_items">
        <id name="id" type="string" unsaved-value="null" >
            <column name="id" sql-type="char(32)" 
                       not-null="true"/>
            <generator class="uuid.hex"/>
        </id>
        <property name="orderId" insert="false" 
                     update="false">
            <column name="order_id" sql-type="char(32)" 
                       not-null="true"/>
        </property>
        <property name="productId" insert="false" 
                     update="false">
            <column name="product_id" sql-type="char(32)" 
                       not-null="true"/>
        </property>
        <property name="amount">
            <column name="amount" sql-type="int" 
                       not-null="true"/>
        </property>
        <property name="price">
            <column name="price" sql-type="double" 
                       not-null="true"/>
        </property>
        <many-to-one name="order" 
                 class="test.hibernate.Order" 
                 column="order_id" />
        <many-to-one name="product" 
                 class="test.hibernate.Product" 
                 cascade="save-update" 
                 column="product_id"/>
    </class>
</hibernate-mapping>

우리는 지금부터 <id>와 <property>요소에 대해서 모두 알고 있다. 하지만 <many-to-one>는 새로운 것이다. 이것은 상당히 간단하다. <many-to-one>요소의 첫번째 사용은 order이라고 불리는 OrderItem의 필드를 test.hibernate.Order의 타입이라고 지칭하고 order_items테이블로 부터 order_id칼럼을 통해 참조한다(element클래스의 테이블 속성을 보라). 두번째 <many-to-one>요소는 cascade="save-update" 속성을 가지는것을 제외하면 첫번째것과 유사하다. 이것은 정의되기 전에 설명되었다. 이런경우에 우리는 OrderItem이 저장되거나(혹은 생성되거나) 수정되거나(혹은 변경되거나) 또는 삭제된것이 없을때 하이버네이트가 Products의 변경을 전해야 한다는것을 말한다. 그리고 위에서 언급된것처럼 복잡한 SQL문에 대한 걱정은 한개의 속성에 요약이 된다.

사용 예제#

Order을 생성하라. 이 예제에서 우리는 Order을 생성하고 유지한다. 각각의 성공적인 Order생성후에 얼마나 Product의 양이 변경되는지 보기 위해 이 예제를 한번 이상 실행 시켜라.

// ...
Configuration cfg = new Configuration()
                    .addClass(Product.class)
                    .addClass(Order.class)
                    .addClass(OrderItem.class);

// ...
Order order = new Order();
order.addProduct(milk, 3);
order.addProduct(coffee, 5);

// ...
sess = sf.openSession();
Transaction t = sess.beginTransaction();
sess.save(order);
t.commit();
sess.close();

System.out.println(order);
// ...

가격 범위내에서 Orders를 찾아라. 이 예제에서 우리는 두개의 파라미터를 가지는 쿼리문을 사용하는 방법을 본다. 하이버네이트는 선호하는 OrderItems와 Products와 함께 정확하게 Orders을 가져온다.

// ...
String query = "select o from o "
    "in class test.hibernate.Order "
    "where o.priceTotal > :priceTotalLower "
    "and o.priceTotal < :priceTotalUpper";

// ...                
Query q = sess.createQuery(query);
q.setDouble("priceTotalLower"
             Double.parseDouble(args[0]));
q.setDouble("priceTotalUpper"
             Double.parseDouble(args[1]));

List list = q.list();
// ...
sess.close();
// ...

가격 범위내에서 Orders을 삭제하라. 이것은 중요한 예제다. 여기서 우리는 하이버네이트가 지적인 툴임을 볼수 있는 방법을 본다. 위에서 언급한것처럼 Order를 삭제할때 이것의 OrderItems는 삭제될 필요가 있다. 하지만 Products는 변경되지 말아야 한다. 이 예제후에 Product가 그대로인것을 확인해 보기 우해서 당신의 데이터베이스를 확인하라.

 // ...
String query = "select o from o "
    "in class test.hibernate.Order "
    "where o.priceTotal > :priceTotalLower "
    "and o.priceTotal < :priceTotalUpper";

Transaction tx = sess.beginTransaction();
sess.delete(query, 
    new Object[]{new Double(args[0])
                 new Double(args[1])}
    new Type[]{Hibernate.DOUBLE, 
               Hibernate.DOUBLE}
           );       
tx.commit();
sess.close();

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-1) was last changed on 06-Apr-2006 09:45 by UnknownAuthor