Изменение редактора Request Factory GWT не сохраняет связанные объекты JDO

Я использую (и новичок) RequestFactory в GWT 2.5 с сущностями JDO с отношением «один ко многим» в хранилище данных AppEngine. Я только начал использовать GWT RequestFactoryEditorDriver для отображения/редактирования моих объектов.

Драйвер отлично обходит мои объекты и правильно их отображает. Однако, когда я пытаюсь изменить значение «связанных» объектов, изменение не сохраняется в хранилище данных.

Когда я изменяю b.name в своем пользовательском интерфейсе и нажимаю «сохранить», я замечаю, что вызывается только вызов persist() A. Метод persist() никогда не вызывается. Как заставить editorDriver срабатывать как в контексте запроса ARequest, так и в контексте запроса BRequest? (поскольку я хочу, чтобы B вызывал InstanceRequest<AProxy,Void> persist(), когда мои изменения относятся только к объектам B.)

Кроме того, AFAICT, если у меня есть редактор на BProxy, любой объект b, который отображается редактором (и в соответствии с контрактом редактора), должен автоматически быть «context.edit (b)» драйвером, чтобы сделать его изменяемым. Однако в моем случае «контекст» — это ARequest, а не BRequest.

Нужно ли мне создавать ValueAwareEditor, как указано здесь: фреймворк редактора GWT и создавать новый BRequest внутри flush() вызвать и запустить его, чтобы изменения в B отдельно сохранялись в BRequest до запуска ARequest?

editorDriver.getPaths() дает мне: "бс"

Кроме того, драйвер определенно видит изменение свойства B, так как editorDriver.isChanged() возвращает значение true до того, как я выполню вызов контекста.

В моих журналах на стороне клиента или на стороне сервера нет ошибок, а обработчик аннотаций работает без предупреждений.

Вот как я устанавливаю свой драйвер:

editorDriver = GWT.create(Driver.class);
editorDriver.initialize(rf, view.getAEditor());

final ARequest aRequest = rf.ARequest();
        final Request<List<AProxy>> aRequest = aRequest.findAByUser(loginInfo.getUserId());
        String[] paths = editorDriver.getPaths();
        aRequest.with(paths).fire(new Receiver<List<AProxy>>() {

            @Override
            public void onSuccess(List<AProxy> response) {
                AProxy a = response.get(0);
                ARequest aRequest2 = rf.aRequest();
                editorDriver.edit(a, aRequest2);
                aRequest2.persist().using(a);
            }
        });

Вот как выглядят мои объекты:

public abstract class PersistentEntity {
    public Void persist() {
        PersistenceManager pm = getPersistenceManager();
        try {
            pm.makePersistent(this);
        } finally {
          pm.close();
        }
        return null;
    }


    public Void remove() {
        PersistenceManager pm = getPersistenceManager();
        try {
            pm.deletePersistent(this);
        } finally {
          pm.close();
        }
        return null;
    }
}

@PersistenceCapable(identityType = IdentityType.APPLICATION)
@Version(strategy=VersionStrategy.VERSION_NUMBER, column="VERSION",
         extensions={@Extension(vendorName="datanucleus", key="field-name", value="version")})

public class A extends PersistentEntity {

        ... (Id, version omitted for brevity)
    @Persistent
    private String name;

        @Persistent
        private List<B> bs;

    public String getName() {
        return name;
    }

        ...

    public void setName(String name) {
        this.name = name;
    }

    public List<B> getBs() {
        return bs;
    }

    public void setBs(List<B> bs) {
        this.bs = bs;
    }

}

... (same annotations as above omitted for brevity)

public class B extends PersistentEntity {

        ... (Id, version omitted for brevity)
    @Persistent
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Вот прокси:

@ProxyFor(A.class)
public interface AProxy extends EntityProxy {
    String getName();
    List<BProxy> getBs();
    void setName(String name);
    void setBs(List<BProxy> bs);
}

@ProxyFor(B.class)
public interface BProxy extends EntityProxy {
    String getName();
    void setName(String name);
}

Вот мои сервисные заглушки:

@Service(A.class)
public interface ARequest extends RequestContext {

    Request<List<A>> findAByUser(String userId);

    InstanceRequest<AProxy, Void> persist();
    InstanceRequest<AProxy, Void> remove();
}

@Service(B.class)
public interface BRequest extends RequestContext {

    Request<List<A>> findB(String key);

    InstanceRequest<BProxy, Void> persist();
    InstanceRequest<BProxy, Void> remove();
}

Изменить: теперь я изменил свой интерфейс ARequest и реализацию службы, чтобы поддерживать метод "saveAndReturn", чтобы я мог рекурсивно "сохранять" "a" на стороне сервера:

Request<UserSandboxProxy> saveAndReturn(AProxy aProxy);

Теперь я обнаружил, что когда я «сбрасываю» свой RequestFactoryEditorDriver, объект контекста на стороне клиента имеет мое новое значение «b.name». Однако, если я вызову «context.fire()» и проверю свой метод «saveAndReturn» на стороне сервера, результирующий объект «a» на стороне сервера, непосредственно перед тем, как я «сохраню» его, не будет содержать изменение на « b.name" в любом элементе списка.

Почему это могло происходить? Как мне отладить, почему эта информация о клиенте не передается по сети на сервер?

Варианты, которые я рассматривал, пробовал и исключал:

1) Убедитесь, что APT запущен и нет предупреждений/ошибок на прокси-интерфейсах или сервисных интерфейсах.

2) Убедитесь, что мои прокси имеют действительный сеттер в AProxy для списка


person yaraju    schedule 26.12.2012    source источник
comment
Используете ли вы шаблон OpenSessionInView (также известный как сеанс на запрос)? В случае JDO это означает, что один PersistenceManager охватывает весь HTTP-запрос.   -  person Thomas Broyer    schedule 28.12.2012
comment
@ThomasBroyer Нет, не я. На данный момент у меня есть этот метод: private static PersistenceManager getPM() { return JDOHelper.getPersistenceManagerFactory("transactions-optional").getPersistenceManager(); } И я вызываю его для каждой операции DAO, такой как persist() и т. д., и pm.close(), как только эта операция завершается. Но независимо от того, выполняется ли persist() правильно, не должен ли я, по крайней мере, при отладке видеть, что мой объект на стороне сервера (предварительно сохраненный) имеет мое измененное значение? Как на это влияет то, использую ли я OSIV? Я попробовал обе настройки операций a.name и b.name из только что загруженного приложения.   -  person yaraju    schedule 29.12.2012


Ответы (1)


Вы должны использовать шаблон "сеанс на запрос", чтобы RequestFactory работал правильно. Подробнее здесь: https://code.google.com/p/google-web-toolkit/issues/detail?id=7827

person Thomas Broyer    schedule 30.12.2012
comment
Потрясающий! Большое спасибо, Томас! Наконец, я использовал Guice с экземпляром PersistenceManager RequestScoped для реализации этого. - person yaraju; 02.01.2013