天天看点

Hibernate one-to-one 复合主键相同的mapping文件配置方法

两张表具有相同的复合主键,且一个表的主键是另外一个表的外键

这个问题困扰了我很久,后来在Google上搜索了很久,终于找到了问题的答案,经过测试,确实可以正确使用。在这里记录下来,方便自己和大家。

问题是这样的:

例如两张表 PRODUCTS和TRANSLATIONS

两张表结构的sql语句为:

create table Products (
        sku varchar(128) not null,
        manuf integer not null,
        catalog varchar(128) not null,
        primary key (sku, manuf, catalog)
    );

create table Translations (
        sku varchar(128) not null,
        manuf integer not null,
        catalog varchar(128) not null,
        DESC varchar(255),
        primary key (sku, manuf, catalog)
    );

alter table Products 
        add constraint FKC8063584DF6EA216 
        foreign key (sku, manuf, catalog) 
        references Translations;
           

表Products和表Translations具有相同的联合主键:(sku, manuf, catalog),且表Products表的主键是引用表Translations的外键。

由于这两个表具有相同的主键,所以两个表的实体类需要相同的联合主键类。对于这两个表的实体类可以这样表示:

首先需要定义好主键类,主键类需要继承java.io.Serializable接口,且需要重写equals和hashcode方法。

ProductId.java

package hello;

import java.io.Serializable;

/**
 * Created by orz on 16-2-28.
 */
public class ProductId implements Serializable {
    private static final long serialVersionUID = 1L;
    private String sku;
    private int manuf;

    private String catalog;

    public String getSku() {
        return sku;
    }

    public void setSku(String sku) {
        this.sku = sku;
    }

    public int getManuf() {
        return manuf;
    }

    public void setManuf(int manuf) {
        this.manuf = manuf;
    }

    public String getCatalog() {
        return catalog;
    }

    public void setCatalog(String catalog) {
        this.catalog = catalog;
    }

    public boolean equals(Object other) {
        if (other == null)
            return false;
        if (!this.getClass().equals(other.getClass()))
            return false;
        ProductId otherId = (ProductId) other;
        if (this.catalog.equals(otherId.catalog) && this.manuf == otherId.manuf
                && this.sku.equals(otherId.sku)) {
            return true;
        } else
            return false;
    }

    public int hashCode() {
        int result;
        result = catalog.hashCode();
        result = 29 * result + manuf;
        result = 29 * result + sku.hashCode();
        return result;
    }
}
           

Product.java

package hello;

/**
 * Created by orz on 16-2-28.
 */
public class Product {
    private ProductId id;

    public ProductId getId() {
        return id;
    }

    public void setId(ProductId id) {
        this.id = id;
    }

    public Translation getTranslation() {
        return translation;
    }

    public void setTranslation(Translation translation) {
        this.translation = translation;
    }

    private Translation translation;
}
           

Translation.java

package hello;

/**
 * Created by orz on 16-2-28.
 */
public class Translation {
    private ProductId id;
    private String description;

    public ProductId getId() {
        return id;
    }

    public void setId(ProductId id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
           

那么下面开始定义其配置文件:

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-3.0.dtd">
<hibernate-mapping>
    <class name="hello.Product" table="Products">
        <composite-id class="hello.ProductId" name="id">
            <key-property name="sku" type="string">
                <column length="128" name="sku"/>
            </key-property>
            <key-property name="manuf" type="int">
                <column name="manuf"/>
            </key-property>
            <key-property name="catalog" type="string">
                <column length="128" name="catalog"/>
            </key-property>
        </composite-id>
        <one-to-one name="translation" constrained="true" class="hello.Translation" cascade="save-update"/>
    </class>
</hibernate-mapping>
           

注意one-to-one其中的constraint="true"属性的配置,表明这个是引用的Translation的外键约束

Translation.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="hello.Translation" table="Translations">
        <composite-id class="hello.ProductId" name="id">
            <key-property name="sku" type="string">
                <column length="128" name="sku"/>
            </key-property>
            <key-property name="manuf" type="int">
                <column name="manuf"/>
            </key-property>
            <key-property name="catalog" type="string">
                <column length="128" name="catalog"/>
            </key-property>
        </composite-id>
        <property name="description" column="DESC"></property>
    </class>
</hibernate-mapping>
           

好了,这样就可以了。可以用测试类测试一下。

package hello;

import org.hibernate.Session;
import org.hibernate.Transaction;
import persistence.HibernateUtil;

import java.util.Iterator;
import java.util.List;

/**
 * Created by orz on 16-2-21.
 */
public class HelloWorld {
    public static void main(String[] args) {
        Session productSession1 = HibernateUtil.getSessionFactory().openSession();
        Transaction productTransaction1 = productSession1.beginTransaction();

        ProductId pid = new ProductId();
        pid.setCatalog("catalog");
        pid.setManuf(11);
        pid.setSku("sku");

        Translation translation = new Translation();
        translation.setId(pid);
        translation.setDescription("description");

        Product testProduct = new Product();
        testProduct.setId(pid);
        testProduct.setTranslation(translation);

        ProductId pid2 = new ProductId();
        pid2.setCatalog("catalog2");
        pid2.setManuf(22);
        pid2.setSku("sku2");

        Translation translation2 = new Translation();
        translation2.setId(pid2);
        translation2.setDescription("description2");

        Product testProduct2 = new Product();
        testProduct2.setId(pid2);
        testProduct2.setTranslation(translation2);

        productSession1.save(testProduct);
        productSession1.save(testProduct2);
        productTransaction1.commit();
        productSession1.close();

        Session productSession2 = HibernateUtil.getSessionFactory().openSession();
        Transaction productTransaction2 = productSession2.beginTransaction();

        List products = productSession2.createQuery("from Product p ").list();

        System.out.println(products.size() + " product(s) found");
        for (Iterator iter = products.iterator(); iter.hasNext();) {
            Product product = (Product) iter.next();
            System.out.println("Product: " + product.getId().getSku() + ", "
                    + product.getId().getManuf() + ", " + product.getId().getCatalog()
                    +", translation: " + product.getTranslation().getDescription());
        }

        productTransaction2.commit();;
        productSession2.close();
        //Shutting down the application
        HibernateUtil.shutdown();
    }
}
           

其中用到的HibernateUtil类就是通用的一个很简单的类。这里也给出来吧,方便大家测试

package persistence;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * Created by orz on 16-2-21.
 */
public class HibernateUtil {
    private static SessionFactory sessionFactory;

    static {
        try {
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
          throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        //Alternatively,you could look up in JNDI here
        return sessionFactory;
    }

    public static void shutdown() {
        //Close caches and connection pools
        getSessionFactory().close();
    }
}
           

这个经过测试,这样配置是可以成功运行的。问题解决。

继续阅读