因此,我发现 OpenJPA (2.1.1) 和 Hibernate (3.3.1) 与 EntityManager.merge 的行为存在重大差异。考虑以下类:
@Entity(name = "ChoiceHolder")
@Table(name = "CHOICEHOLDER")
@Inheritance(strategy = InheritanceType.JOINED)
public class ChoiceHolder
implements Equals, HashCode
{
protected int id;
protected String choice3;
protected String choice4;
@Id
@Column(name = "ID", scale = 0)
public int getId() {
return id;
}
public void setId(int value) {
this.id = value;
}
@Basic
@Column(name = "CHOICE3", length = 255)
public String getChoice3() {
return choice3;
}
public void setChoice3(String value) {
this.choice3 = value;
}
@Basic
@Column(name = "CHOICE4", length = 255)
public String getChoice4() {
return choice4;
}
}
并考虑以下客户端代码(这只是一个 SSCCE - 在我的实际用例中,使用相同 ID 合并的两个调用反映了从两个单独的客户端操作接收到的数据,其中 id 在两个操作之间是相同的):
ChoiceHolder holder1a = new ChoiceHolder();
holder1a.setId(1);
holder1a.setChoice3("foo");
ChoiceHolder holder1b = new ChoiceHolder();
holder1b.setId(1);
holder1b.setChoice4("bar");
EntityManager em1 = factory.createEntityManager();
em1.merge(holder1a);
em1.close();
EntityManager em2 = factory.createEntityManager();
em2.merge(holder1b);
em2.close();
EntityManager em1Find = factory.createEntityManager();
ChoiceHolder holder1result = em1Find.find(ChoiceHolder.class, 1);
em1find.close();
ChoiceHolder holder2a = new ChoiceHolder();
holder2a.setId(2);
holder2a.setChoice3("foo2");
ChoiceHolder holder2b = new ChoiceHolder();
holder2b.setId(2);
holder2b.setChoice4("bar2");
EntityManager em3 = factory.createEntityManager();
em3.merge(holder2a);
em3.merge(holder2b);
em3.close();
EntityManager em2Find = factory.createEntityManager();
ChoiceHolder holder2result = em2Find.find(ChoiceHolder.class, 2);
em2Find.close();
当我使用 Hibernate 运行上述代码时,holder1result
choice3 为 null,choice4 为“bar”。同样,holder2result
choice3 为 null,choice4 为 "bar2"。但是,当我使用 openJPA 运行相同的代码时,我得到了一些非常不同的东西:holder1result
同时设置了choice3 和choice4,并且调用会em3.merge(holder2b)
因 ReportingSQLException 而爆炸,因为它尝试执行的 INSERT 违反了对choiceholder ID 的主键约束。
如果重要的话,以下是我用来配置 Hibernate 的属性文件中的相关位:
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.connection.driver_class=org.postgresql.Driver
hibernate.hbm2ddl.auto=create-drop
hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
hibernate.jdbc.batch_size=0
这是我的 persistence.xml 中用于配置 openJPA 的相应位:
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
<property name="openjpa.jdbc.DBDictionary" value="postgres"/>
<property name="openjpa.ConnectionDriverName" value="org.postgresql.Driver"/>
<property name="openjpa.jdbc.MappingDefaults" value="DeferConstraints=true,ForeignKeyDeleteAction=restrict,JoinForeignKeyDeleteAction=restrict"/>
在我的特殊情况下,我想要的是我在 Hibernate 中看到的行为;但是,我的环境(在 Karaf 内部)要求我改用 OpenJPA。是否可以在 OpenJPA 上设置标志来更改其行为以匹配我正在寻找的内容?
这是对 JPA 的可怕滥用吗?如果是,我应该使用其他一些技术/调用序列吗?
提前致谢!