我是JPA和Hibernate的新手。我有两个实体,供应商和产品,如下所述。
@Entity
public class Vendor extends BaseEntity
{
private static final long serialVersionUID = 267250313080292374L;
@NotNull
private String name;
@NotNull
private String city;
@OneToMany(mappedBy = "vendor", cascade = CascadeType.ALL)
private List<Product> products = new ArrayList<Product>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}
@Entity
public class Product extends BaseEntity
{
private static final long serialVersionUID = -4676899182130380017L;
@NotNull
private String name;
@Column(nullable = false, precision = 10, scale = 2)
private double price;
@NotNull
private int quantity;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="VENDOR_ID", nullable = false)
private Vendor vendor;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Vendor getVendor() {
return vendor;
}
public void setVendor(Vendor vendor) {
this.vendor = vendor;
}
}
我的问题与@ManyToOne注释中属性nullable = false
的使用有关。我希望用@ManyToOne注释的相应列不为null。但是,当我通过以下测试测试实体的持久性时:
public void testCreateEntity()
{
// create vendor1, set name and city
vendor1 = new Vendor();
vendor1.setName("MediaMarkt");
vendor1.setCity("Berlin");
vendor1 = service.createOrUpdateEntity(vendor1);
// create product1, set name, price and quantity
product1 = new Product();
product1.setName("Samsung Galaxy S7");
product1.setPrice(new Double("819.00"));
product1.setQuantity(1);
vendor1.getProducts().add(product1);
product1.setVendor(vendor1);
// create product at service
product1 = service.createOrUpdateEntity(product1);
...
}
其中createOrUpdateEntity方法是DAO Bean对象的一部分
@PersistenceContext
private EntityManager em;
public <T extends BaseEntity> T createOrUpdateEntity(T entity)
{
// as we have no id yet, it must be freshly brewed
if (entity.getId() == 0)
{
log.debug("createOrUpdateEntity::create:: {}", entity);
this.em.persist(entity);
}
// if there is an id, we must have dealt with it before
else
{
log.debug("createOrUpdateEntity::update:: {}", entity);
this.em.merge(entity);
}
this.em.flush();
return entity;
}
我收到错误:
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: de.brockhaus.stock.entity.Stock at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:765) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:758) at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80) at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:398) at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:162) at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:111) at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:425) at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:249) at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121) at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) ... 138 more
编辑:实现这个example,它使用注释为nullable = false的@ManyToOne列,我意识到我的问题与此无关。如前面的服务器日志所示,问题是由Cascade类引起的。 SO中的一些solutions建议通过CascadeType.MERGE更改CascadeType.ALL。其他ones显示不同的策略。甚至一些ones告诉我只有关联的OneToMany端应该使用级联。坦率地说,我认为在关联的两侧使用CascadeType.ALL是最好的选择。但似乎我错了。虽然,正如我已经指出的那样,我是JPA和Hibernate的新手,我不明白这些推理。
答案 0 :(得分:1)
您可以使用 optional
标记进行空值控制:
@ManyToOne(cascade = CascadeType.ALL, optional = false)
@JoinColumn(name="VENDOR_ID")
private Vendor vendor;
答案 1 :(得分:1)
实际上,使用此代码,我可以让您的示例起作用:
的pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>demo</groupId>
<artifactId>hibernate4-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>hibernate4-demo</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hibernate-core.version>4.3.11.Final</hibernate-core.version>
</properties>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate-core.version}</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate-core.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
BaseEntity.java(简称Brockhaus)
包demo.hibernate4;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;
@MappedSuperclass
public abstract class BaseEntity implements Serializable {
@Version
private long version;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Temporal(TemporalType.DATE)
private Date creationDate;
public BaseEntity() {
//lazy
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public long getId() {
return id;
}
}
GenericDAOBean.java
package demo.hibernate4;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
public class GenericDAOBean {
private EntityManager em;
@Override
public <T extends BaseEntity> T createOrUpdateEntity(T entity) {
if (entity.getId() == 0) {
this.em.persist(entity);
} else {
this.em.merge(entity);
}
this.em.flush();
return entity;
}
public void setEm(EntityManager em) {
this.em = em;
}
}
的persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="hibernate4-demo" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/mysql?zeroDateTimeBehavior=convertToNull"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
<property name="javax.persistence.schema-generation.database.action" value="none"/>
</properties>
</persistence-unit>
</persistence>
Main.java
package demo.hibernate4;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class Main {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hibernate4-demo");
EntityManager em = emf.createEntityManager();
GenericDAOBean service = new GenericDAOBean();
service.setEm(em);
EntityTransaction transaction = em.getTransaction();
transaction.begin();
// create vendor1, set name and city
Vendor vendor1 = new Vendor();
vendor1.setName("MediaMarkt");
vendor1.setCity("Berlin");
vendor1 = service.createOrUpdateEntity(vendor1);
// create product1, set name, price and quantity
Product product1 = new Product();
product1.setName("Samsung Galaxy S7");
product1.setPrice(new Double("819.00"));
product1.setQuantity(1);
vendor1.getProducts().add(product1);
product1.setVendor(vendor1);
// create product at service
product1 = service.createOrUpdateEntity(product1);
transaction.commit();
System.exit(0);
}
}
使用此代码和映射,我在MySQL中得到2行,并建立了产品与供应商之间的关系。
但是,我并不了解您尝试使用供应商密钥列表实现的目标。目前,表PRODUCT_VENDORKEY保持空白。
您必须进一步描述您的背景。