两张表具有相同的复合主键,且一个表的主键是另外一个表的外键
这个问题困扰了我很久,后来在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();
}
}
这个经过测试,这样配置是可以成功运行的。问题解决。