6

我在我们的服务层中有这段代码:

@Override
public <T extends BaseEntity> T find(Long id, Class<? extends BaseEntity> clazz) throws Exception {
    BaseEntity e = em.find(clazz, id);
    if (e != null) {
        deserialize(e, e.getClass());
    } else
        LOG.error("Found null for id " + id);
    return (T) e;
}

public void delete(BaseEntity e, String index, String type) throws Exception {
    if (e == null)
        return;
    if (e.getId() == null)
        return;
    Delete delete = new Delete.Builder(e.getId().toString()).index(index).type(type).build();
    getJestClient().execute(delete);
    if (em.contains(e)) {
        em.remove(e);
    } else {
        BaseEntity ee = find(e.getId(), e.getClass());
        em.remove(ee);
    }
}

 protected void deserialize(BaseEntity dst, Class<?> dstClass) throws Exception {
    Object src  = serializer.deserialize(new String(dst.getContent(), "UTF-8"), dstClass);

    for (Field f : getClassFields(src.getClass())) {
        if (Modifier.isStatic(f.getModifiers())) continue;
        if (!f.isAnnotationPresent(Expose.class)) continue;

        f.setAccessible(true);

        f.set(dst, f.get(src));
        LOG.trace("deserializing " + f.getName() + " : " + f.get(src));
    }
}

但是,如果我用它来删除实体,它将失败:

Caused by: java.lang.IllegalArgumentException: Removing a detached instance FooEntity
at org.hibernate.ejb.event.EJB3DeleteEventListener.performDetachedEntityDeletionCheck(EJB3DeleteEventListener.java:65)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:107)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:73)
at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:956)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:934)
at org.hibernate.ejb.AbstractEntityManagerImpl.remove(AbstractEntityManagerImpl.java:867)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy42.remove(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy31.remove(Unknown Source)
... 16 more

但这对我来说毫无意义,因为之前的行em.remove(ee),实体是通过 find 方法加载的,因此它不能被分离......事务是通过 spring xml 配置实现的

// 编辑:添加反序列化方法。基本上,它将获取与每个对象一起存储的 json 内容并创建对象的副本,然后将字段分配给该副本。getJestClient().execute 是 elasticsearch 的 handler,与 hibernate 和 jpa 无关。

Em 是通过 spring 创建的:

 <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dsFoo">
    <property name="driverClassName" value="${foo.census.driverClassName}"/>
    <property name="url" value="${foo.census.url}"/>
    <property name="username" value="${foo.census.user}"/>
    <property name="password"   value="${foo.census.password}"/>
    <property name="testOnBorrow" value="true"/>
    <property name="testOnReturn" value="true"/>
    <property name="testWhileIdle" value="true"/>
    <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
    <property name="numTestsPerEvictionRun" value="3"/>
    <property name="minEvictableIdleTimeMillis" value="1800000"/>
    <property name="validationQuery" value="SELECT 1"/>
</bean>

<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="emfCensus">
    <property name="persistenceUnitName" value="puFoo"/>
    <property name="dataSource"          ref="dsFoo"/>
</bean>

<bean id="emFoo" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
    <property name = "entityManagerFactory" ref="emfFoo"/>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="emfFoo" />
    <property name="persistenceUnitName"  value="puFoo" />
</bean>

<bean id="repoFoo" class="service.FooService">
    <property name="entityManager" ref="emFoo" />
</bean>

<aop:aspectj-autoproxy proxy-target-class="true"/>

<aop:config>
    <aop:pointcut id="repoFooOperation" expression="execution(* service.FooService.*(..))"/>
    <aop:advisor advice-ref="txAdviceFoo" pointcut-ref="repoFooOperation"/>
</aop:config>

<tx:advice id="txAdviceFoo" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>
4

1 回答 1

9

好的,感谢 stackoverflow 和谷歌搜索,我设法找到了解决它的方法:

    if (em.contains(e)) {
        em.remove(e);
    } else {
        BaseEntity ee = em.getReference(e.getClass(), e.getId());
        em.remove(ee);
    }

是删除分离的实体的正确方法。

于 2013-10-31T13:35:31.537 回答