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 は、hibernate や jpa とは関係のない Elasticsearch のハンドラーです。

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 に答える