【问题标题】:How To Delete an Object With Persistent/Non-Persistent Collection Field That is null?如何删除持久/非持久集合字段为空的对象?
【发布时间】:2023-03-16 07:17:02
【问题描述】:

我有一个名为 Parent 的类,我将这些对象存储在高复制数据存储中。

每个对象与我通过存储 Key 对象列表来管理的 对象具有无主关系。

我有一个 REST Web 服务,它以 JSON 表示形式返回父对象和所有子对象。为了使用 Jackson marshaller,我获取 Child 对象的集合,并使用未定义参数化类型的原始 Collection 将该集合添加到 Parent。

Collection 字段不是我打算坚持的。然而,因为According to DataNucleus's Andy, Google's JDO @Persistent documentation is potentially incorrect,我没有在该字段上放置@NotPersistent 注释。现在我在数据存储中有用户数据,需要注意不要通过修改 Parent 类意外破坏它。我不确定这是否可能或是否会发生,所以我会谨慎行事。

在这个空的Collection cardList值中没有存储数据;但是,我经常收到关于无法分离字段的错误。

  • 如果字段上没有任何注释(根据 Andy 的说法,默认为 @Persistent),我无法删除该对象。
  • 如果我将@NotPersistent 放在该字段上,则无法访问任何数据,也没有任何作用。

这是“父母”类:

public class Parent implements Serializable {

    private static final long serialVersionUID = 1L;    

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    @Persistent
    private String keyString;

    @Persistent
    private String name; 

    // store keys that associate with Child objects
    @Persistent 
    private List<Key> childRealKeys = new ArrayList<Key>();

    /** 
     * If @NotPersistent, no Parent is accessible.
     * If @NotPersistent is commented, the data loads, but I cannot delete the parent.
     *
     * This field was not intended to be stored and is just used to serialize the Parent
     * and Children to a single JSON object to be returned in a REST call.
     */
     // @NotPersistent
     private Collection childList = null;

     // getter for the field I don't want to store but just use to return children in the REST service as JSON
     public Collection getChildList() { return childList; }

     // remaining getters and setters follow ...

这是我用来删除对象的代码

public void deleteParent(String keyString) {

    PersistenceManager pm = PMF.getInstance().getPersistenceManager();
    Parent parent = null;

    Key parentKey = KeyFactory.stringToKey(keyString);
    parent = pm.getObjectById(Parent.class, parentKey);

    // I tried detaching to see if that helps. It still says the field is not detached!
    Parent detachedParent = pm.detachCopy(parent);
    pm.deletePersistent(detachedParent.getChildList());
    pm.deletePersistent(detachedParent);

    pm.close();

}

尝试删除对象时的 StackTrace:

请注意,此字段没有存储任何数据。我似乎也无法成功分离该字段。

javax.jdo.JDODetachedFieldAccessException: You have just attempted to access field "childList" yet this field was not detached when you detached the object. Either dont access this field, or detach it when detaching the object.
at com.fullcreative.loop.Parent.jdoGetChildList(Parent.java)
at com.fullcreative.loop.Parent.getChildList(Parent.java:112)
at com.fullcreative.loop.LoopDaoJdo.deleteParent(LoopDaoJdo.java:690)
at com.fullcreative.loop.LoopService.deleteParent(LoopService.java:551)
at com.fullcreative.loop.LoopController.deleteParent(LoopController.java:1022)
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 com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:104)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:582)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:643)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:369)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at com.fullcreative.loop.security.auth.GaeAuthenticationFilter.doFilter(GaeAuthenticationFilter.java:227)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:168)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:35)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:60)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:97)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:78)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:362)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

问题:

  • 如何删除父对象?

  • 我需要做什么才能从数据存储中删除 null Collection 字段而不丢失所有数据?我觉得最好的方法可能是使用 2 个独立但镜像的对象:一个用于将父键和子键存储在数据存储中,另一个用于将父键和所有关联的子键作为 JSON 表示返回。

  • 有没有办法追溯使 Collection cardList 字段 NotPersistent 以便我可以使用它来序列化前端的数据?

【问题讨论】:

  • 不确定这是否有帮助,但是当我在 childList 集合上使用 @NotPersistent 运行时,我得到:'Class "" is not found in the CLASSPATH.'作为 JDOException。

标签: java google-app-engine jdo datanucleus


【解决方案1】:

如果您的 Collection 仅用于以瞬时方式转换 @Persistent childRealKeys,那么它应该是 @NotPersistent childList。

在这种情况下:

// pm.deletePersistent(detachedParent.getChildList()); becomes unnecessary, and
pm.deletePersistent(parent); //should work

在这种情况下,你会遇到另一个例外吗?

@jmort253 更新:

检查以确保项目中不包含重复的 appengine JAR 文件。我之前升级了一些旧的 JARS 并没有从 CLASSPATH 中删除。类加载器可能会加载旧版本并忽略新版本,这发生在我的案例中。事实证明,解决依赖关系可以解决问题。

此外,然后我可以毫无问题地使用@NotPersistent,并且可以使用事务和PMF DataNucleus DetachOnClose property 作为Andy describes in this Google Group 分离对象。

删除父级

public boolean deleteLoop(String parentId) {
    PersistenceManager pm = PMF.getInstance().getPersistenceManager();
    Transaction tx = pm.currentTransaction();
    try {
        tx.begin();
        pm.setDetachAllOnCommit(true);
        Parent parent = null;

        Key parentKey = KeyFactory.stringToKey(parentId);
        loop = pm.getObjectById(Parent.class, parentKey);

        Parent detachedParent = pm.detachCopy(parent);

                    // this was indeed not necessary
        //pm.deletePersistent(detachedParent.getChildList());

                    // no detachment issues, object deletes just fine.
        pm.deletePersistent(detachedParent);

        tx.commit();
        //pm.close();

    } catch(Exception e) {
        log.error("Exception trying to delete Parent :: ",e);
        e.printStackTrace();


    } finally {

        if(tx.isActive()) {
            tx.rollback();
        }

        pm.close();
    }
}

父类:

现在可以添加 @NotPersistent 而不会收到类路径警告。除了 JAR 依赖问题之外,我还必须在 Collection 定义中添加一个参数化类型。如果省略,您会收到以下警告:

  • 在 CLASSPATH 中找不到类“”。请检查您的规范和 CLASSPATH。

     @PersistenceCapable(detachable = "true")
     public class Parent implements Serializable { 
        ...
        @NotPersistent
        private Collection<Child> childList;
        ...      
     }
    

【讨论】:

  • 是的,我添加了您注释掉的行作为故障排除步骤。这似乎没有什么不同。另外,我在我的问题评论中提到,添加 @NotPersistent 注释导致在 CLASSPATH 中找不到“类”。要抛出 JDOException。
  • 我更新了您的答案并接受了它,因为您添加的内容帮助我最终找到了问题的原因和解决方案。谢谢!
猜你喜欢
  • 2020-12-05
  • 2019-05-26
  • 2015-12-20
  • 1970-01-01
  • 2010-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多