Java 如何从EntityManager分离实体 我的环境

Java 如何从EntityManager分离实体 我的环境,java,hibernate,jpa-2.0,Java,Hibernate,Jpa 2.0,Java7/JPA2/Hibernate5.1 我的情景 我正在构建一个存储库模式实现。所有代码都是编写的,并且在没有错误情况发生时都可以正常工作 但是,假设将三个实体实例添加到存储库中。第一个和第三个可以,但第二个缺少强制(非空)列的值。保存存储库时将返回DB错误 当遇到这种情况时,批处理过程应该只在某个地方写一条日志消息,跳过无效对象并继续处理其他对象。为了做到这一点,只应从存储库中删除此无效实体,这意味着将其与存储库使用的底层EntityManager分离 我的问题 repository.

Java7/JPA2/Hibernate5.1

我的情景 我正在构建一个存储库模式实现。所有代码都是编写的,并且在没有错误情况发生时都可以正常工作

但是,假设将三个实体实例添加到存储库中。第一个和第三个可以,但第二个缺少强制(非空)列的值。保存存储库时将返回DB错误

当遇到这种情况时,批处理过程应该只在某个地方写一条日志消息,跳过无效对象并继续处理其他对象。为了做到这一点,只应从存储库中删除此无效实体,这意味着将其与存储库使用的底层EntityManager分离

我的问题
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();
}