Java 如何从EntityManager分离实体 我的环境
Java7/JPA2/Hibernate5.1 我的情景 我正在构建一个存储库模式实现。所有代码都是编写的,并且在没有错误情况发生时都可以正常工作 但是,假设将三个实体实例添加到存储库中。第一个和第三个可以,但第二个缺少强制(非空)列的值。保存存储库时将返回DB错误 当遇到这种情况时,批处理过程应该只在某个地方写一条日志消息,跳过无效对象并继续处理其他对象。为了做到这一点,只应从存储库中删除此无效实体,这意味着将其与存储库使用的底层EntityManager分离 我的问题Java 如何从EntityManager分离实体 我的环境,java,hibernate,jpa-2.0,Java,Hibernate,Jpa 2.0,Java7/JPA2/Hibernate5.1 我的情景 我正在构建一个存储库模式实现。所有代码都是编写的,并且在没有错误情况发生时都可以正常工作 但是,假设将三个实体实例添加到存储库中。第一个和第三个可以,但第二个缺少强制(非空)列的值。保存存储库时将返回DB错误 当遇到这种情况时,批处理过程应该只在某个地方写一条日志消息,跳过无效对象并继续处理其他对象。为了做到这一点,只应从存储库中删除此无效实体,这意味着将其与存储库使用的底层EntityManager分离 我的问题 repository.
repository.exclude(entity)
方法调用(将实体从EntityManager内部分离)似乎不起作用,第二次尝试保存存储库时再次失败
我的(部分)抽象存储库类
My persistence.xml
不幸的是,在当前的JPA实现AFAIR中,无法断开一个对象与实体管理器的连接 EntityManager.clear()将断开所有JPA对象的连接,因此,如果您计划保持其他对象的连接,那么在所有情况下,这可能不是一个合适的解决方案
因此,最好是克隆对象,并将克隆传递给更改对象的代码。由于默认的克隆机制以适当的方式处理基本的和不可变的对象字段,因此您不必编写大量管道代码(除了深度克隆您可能有的任何聚合结构)。将注释转换为答案: 根据,在拆离实体之前需要
flush()
从OP更新代码:
public void save() throws Exception {
List<T> processedEntities = new ArrayList<T>();
EntityManager entityManager = getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
try {
for(T entity : addedEntities) {
entityManager.persist(entity);
processedEntities.add(entity);
}
for(T entity : updatedEntities)
entityManager.merge(entity);
for(T entity : deletedEntities)
entityManager.merge(entity);
entityManager.flush();
transaction.commit();
} catch(Exception e) {
updatedEntities.addAll(processedEntities);
addedEntities.removeAll(processedEntities);
if(transaction.isActive())
transaction.rollback();
throw e;
}
addedEntities.clear();
updatedEntities.clear();
deletedEntities.clear();
}
public void save()引发异常{
List processedEntities=new ArrayList();
EntityManager EntityManager=getEntityManager();
EntityTransaction=entityManager.getTransaction();
transaction.begin();
试一试{
对于(T实体:附录){
entityManager.persist(实体);
processedEntities.add(实体);
}
对于(T实体:更新的实体)
entityManager.merge(实体);
对于(T实体:删除身份)
entityManager.merge(实体);
entityManager.flush();
commit();
}捕获(例外e){
addAll(processedEntities);
附录。删除所有(处理项);
if(transaction.isActive())
transaction.rollback();
投掷e;
}
addedEntities.clear();
updateIdentities.clear();
deletedEntities.clear();
}
那怎么办?您的事务边界在哪里?@XtremeBaumer:我更喜欢使用JPA,而不是调用特定于Hibernate的方法,除非这是绝对必要的necessary@SimonMartinelli:我刚刚添加了显示的save()
方法that@XtremeBaumer:我决定在Session.execute()上试一试,但这种行为正是同样的错误!detach正是AlexSC所需要的。参见JavaDoc
@PersistenceUnit(unitName = "my-ds")
public class MestreRepository extends AbstractRepository<Mestre, Long> {
public List<Mestre> all() throws Exception {
List<Mestre> result = getEntityManager().createQuery("from Mestre", Mestre.class).getResultList();
return result;
}
}
public class Main {
public static void main(String[] args) {
MestreRepository allMestres = new MestreRepository();
Mestre mestre1 = new Mestre();
mestre1.setNome("Mestre 1");
Mestre mestre2 = new Mestre(); // This one lacks Nome and will fail to be saved
Mestre mestre3 = new Mestre();
mestre3.setNome("Mestre 3");
allMestres.add(mestre1);
allMestres.add(mestre2);
allMestres.add(mestre3);
System.out.println("Saving 3 mestres");
try {
allMestres.save();
System.out.println("All 3 mestres saved"); // never happens!
} catch(Exception e) {
System.out.println("Error when salving 3 mestres");
try {
System.out.println("Excluding mestre 2");
allMestres.exclude(mestre2);
System.out.println("Salving other 2 mestres");
allMestres.save();
System.out.println("All 2 mestres salved"); // never happens!
} catch(Exception e2) {
System.out.println("Still having errors");
}
}
allMestres.close();
}
}
<?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="my-ds" transaction-type="RESOURCE_LOCAL">
<class>domain.Mestre</class>
<class>domain.Detalhe</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<!-- Hibernate properties -->
<property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
<property name="hibernate.connection.url" value="xxx"/>
<property name="hibernate.connection.username" value="yyy"/>
<property name="hibernate.connection.password" value="***"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
</properties>
</persistence-unit>
</persistence>
public void save() throws Exception {
List<T> processedEntities = new ArrayList<T>();
EntityManager entityManager = getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
try {
for(T entity : addedEntities) {
entityManager.persist(entity);
processedEntities.add(entity);
}
for(T entity : updatedEntities)
entityManager.merge(entity);
for(T entity : deletedEntities)
entityManager.merge(entity);
entityManager.flush();
transaction.commit();
} catch(Exception e) {
updatedEntities.addAll(processedEntities);
addedEntities.removeAll(processedEntities);
if(transaction.isActive())
transaction.rollback();
throw e;
}
addedEntities.clear();
updatedEntities.clear();
deletedEntities.clear();
}
public void save() throws Exception {
List<T> processedEntities = new ArrayList<T>();
EntityManager entityManager = getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
try {
for(T entity : addedEntities) {
entityManager.persist(entity);
processedEntities.add(entity);
}
for(T entity : updatedEntities)
entityManager.merge(entity);
for(T entity : deletedEntities)
entityManager.merge(entity);
entityManager.flush();
transaction.commit();
} catch(Exception e) {
updatedEntities.addAll(processedEntities);
addedEntities.removeAll(processedEntities);
if(transaction.isActive())
transaction.rollback();
throw e;
}
addedEntities.clear();
updatedEntities.clear();
deletedEntities.clear();
}