简体   繁体   English

如何删除具有持久性/非持久性收集字段为null的对象?

[英]How To Delete an Object With Persistent/Non-Persistent Collection Field That is null?

I have a class called Parent , and I'm storing these object's in the High replication datastore. 我有一个名为Parent的类,并将这些对象存储在High复制数据存储区中。

Each object has an unowned relationship with child objects that I manage by storing a List of Key objects. 每个对象都与我通过存储Key对象列表管理的对象具有不相关的关系。

I have a REST web service that returns the Parent and all Child objects as a JSON representation. 我有一个REST Web服务,它以JSON表示形式返回Parent和所有Child对象。 In order to use the Jackson marshaller, I take the collection of Child objects and add that collection to the Parent using a raw Collection with no parameterized types defined. 为了使用Jackson编组器,我将使用Child对象的集合,并使用未定义参数化类型的原始Collection将该集合添加到Parent中。

The Collection field was not something I intended to persist. 我不想保留“收集”字段。 Yet, because According to DataNucleus's Andy, Google's JDO @Persistent documentation is potentially incorrect , I didn't put a @NotPersistent annotation on the field. 但是,由于根据DataNucleus的Andy所说,Google的JDO @Persistent文档可能不正确 ,因此我没有在该字段上放置@NotPersistent批注。 Now I have user data in the datastore and need to be careful not to accidentally destroy it by modifying the Parent class. 现在,我在数据存储区中有用户数据,需要注意不要通过修改Parent类而意外破坏它。 I'm not sure if that's possible or if it can happen, so I'm proceeding cautiously. 我不确定这是否可能,所以我在谨慎进行。

There is no data stored in this null Collection cardList value; 此null Collection cardList值中没有存储任何数据。 however, I oftentimes get errors about not being able to detach the field. 但是,我经常会遇到无法分离该字段的错误。

  • Without any annotations on the field, (which according to Andy, defaults to @Persistent), I am unable to delete the object. 在字段上没有任何注释(根据Andy,默认为@Persistent),我无法删除该对象。
  • If I put @NotPersistent on the field, then none of the data can be accessed and nothing works. 如果将@NotPersistent放在该字段上,则无法访问任何数据,并且没有任何效果。

Here is the class "Parent": 这是“父母”类:

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 ...

Here is the code I'm using to delete the object : 这是我用来删除对象的代码

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 when trying to delete object: 尝试删除对象时使用StackTrace:

Note that again, no data is stored for this field. 再次注意,该字段没有数据存储。 I also can't seem to successfully detach the field. 我似乎也无法成功分离该领域。

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)

Questions: 问题:

  • How can I delete the Parent object? 如何删除父对象?

  • What do I need to do to remove the null Collection field from the datastore without losing all my data? 我需要怎么做才能从数据存储中删除空的Collection字段而又不丢失所有数据? I feel like the best approach might be to use 2 separate but mirrored objects: One for storing the parent and child keys in the datastore and another for returning the parent and all associated children as a JSON representation. 我觉得最好的方法可能是使用2个单独但已镜像的对象:一个用于将父键和子键存储在数据存储区中,另一个用于将父键和所有关联的子键作为JSON表示返回。

  • Is there a way to retroactively make the Collection cardList field NotPersistent so I can just use it for serializing data on the frontend? 有没有一种方法可以追溯使Collection cardList字段为NotPersistent,这样我就可以用它来序列化前端的数据了?

If your Collection is only used for transforming @Persistent childRealKeys in a transient way, then it should be @NotPersistent childList. 如果您的Collection仅用于临时转换@Persistent childRealKeys,则它应该是@NotPersistent childList。

In that context: 在这种情况下:

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

Are you getting another exception in that case? 在这种情况下,您是否还有另一个例外?

UPDATE by @jmort253: @ jmort253更新:

Checked to be sure there aren't duplicate appengine JAR files included in the project. 检查以确保项目中没有重复的appengine JAR文件。 I upgraded earlier and some of the older JARS weren't removed from the CLASSPATH. 我已升级较早,而某些较旧的JARS并未从CLASSPATH中删除。 The classloader may load the older versions and ignore the newer versions, and this was happening in my case. 类加载器可能会加载较旧的版本,而忽略较新的版本,在我的情况下就是这种情况。 It turns out that resolving the dependencies takes care of the issue. 事实证明,解决依赖关系可以解决此问题。

Additionally, I can then use @NotPersistent without issues, and I can detach the object using a Transaction and the PMF DataNucleus DetachOnClose property as Andy describes in this Google Group . 此外,然后我可以使用@NotPersistent而不出现问题,并且可以使用事务和PMF DataNucleus DetachOnClose属性(Andy在此Google Group中所述)分离对象。

Deleting Parent : 删除家长

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();
    }
}

Parent Class: 家长班:

Can now add @NotPersistent without getting classpath warnings. 现在可以在不获取类路径警告的情况下添加@NotPersistent。 In addition to the JAR dependency issues, I had to add a parameterized type to the Collection definition. 除了JAR依赖项问题外,我还必须在Collection定义中添加参数化类型。 If it's omitted, you get the following warning: 如果省略,则会收到以下警告:

  • Class "" was not found in the CLASSPATH. 在CLASSPATH中找不到类“”。 Please check your specification and your CLASSPATH. 请检查您的规格和CLASSPATH。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM