Как удалить объект с постоянным / непостоянным полем коллекции, который является нулевым? - PullRequest
0 голосов
/ 23 февраля 2012

У меня есть класс с именем Parent , и я храню эти объекты в хранилище данных высокой репликации.

У каждого объекта есть несобственные отношения с дочерними объектами.которым я управляю, храня список объектов Key .

У меня есть веб-служба REST, которая возвращает родительский и все дочерние объекты в виде представления JSON.Чтобы использовать маршаллера Джексона, я беру коллекцию объектов Child и добавляю эту коллекцию в Parent, используя необработанную коллекцию без заданных параметризованных типов.

Поле Collection не было тем, что я намеревался сохранить.Тем не менее, поскольку По словам Энди из DataNucleus, документация Google JDO @Persistent является потенциально неверной , я не поместил аннотацию @NotPersistent в поле.Теперь у меня есть пользовательские данные в хранилище данных, и я должен быть осторожен, чтобы случайно не уничтожить их, изменив класс Parent.Я не уверен, возможно ли это или может ли это произойти, поэтому я действую осторожно.

Нет данных, хранящихся в этом нулевом Collection cardList ;однако я часто получаю ошибки из-за невозможности отсоединить поле.

  • Без каких-либо аннотаций на поле (который, по словам Энди, по умолчанию равен @Persistent), я не могу удалить объект.
  • Если я добавлю @NotPersistent в поле, тогда ни один из данных не будет доступен, и ничего не будет работать.

Вот класс "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 ...

Вот код, который я использую для удаления объекта :

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)

Вопросы:

  • Как я могу удалить родительский объект?

  • Что мне нужно сделать, чтобы удалить пустое поле «Коллекция» из хранилища данных без потери всех моих данных?Мне кажется, что наилучшим подходом может быть использование 2 отдельных, но зеркальных объектов: один для хранения родительского и дочернего ключей в хранилище данных, а другой для возврата родительского и всех связанных дочерних объектов в виде представления JSON.

  • Есть ли способ задним числом сделать поле Collection cardList NotPersistent, чтобы я мог просто использовать его для сериализации данных во внешнем интерфейсе?

1 Ответ

1 голос
/ 23 февраля 2012

Если ваша коллекция используется только для временного преобразования @Persistent childRealKeys, то это должен быть @NotPersistent childList.

В этом контексте:

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

Получаете ли вы еще одно исключение в этом случае?

ОБНОВЛЕНИЕ @ jmort253:

Проверено, чтобы убедиться, что в проект не включены дубликаты JAR-файлов appengine. Я обновил ранее, и некоторые из старых JARS не были удалены из CLASSPATH. Загрузчик классов может загружать более старые версии и игнорировать более новые версии, и это происходило в моем случае. Оказывается, что решение зависимостей решает проблему.

Кроме того, я могу затем без проблем использовать @NotPersistent и отсоединить объект, используя транзакцию и свойство PMF DataNucleus DetachOnClose , как Энди описывает в этой группе Google .

Удаление родителя :

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