Я внимательно следил за документацией JDO движка приложения, но у меня возникли странные и непоследовательные проблемы с загрузкой постоянной коллекции, содержащейся в моем объекте Board.Несоответствие возникает даже в локальном веб-сервере разработки после того, как я вручную указываю «возможную согласованность» как несуществующую.
Иногда, когда я загружаю свой объект / коллекцию с использованием созданных мной вспомогательных методов загрузки, это не вызывает проблем.В других случаях возвращается пустая коллекция (обратите внимание, что я "касаюсь" коллекции с помощью метода get, чтобы гарантировать, что данные загружаются не просто в объект прокси).
Первоначально я думал, что проблема просто связана с недостатками механизма "возможной согласованности" механизма хранения с высокой репликацией, но после создания собственной политики с возможной согласованностью 0% в LocalServiceTestHelper я вполне уверен, что это неcase.
Я создал тест JUnit, который иллюстрирует эту проблему.По сути, я пытаюсь создать и сохранить фиктивный объект User и Board в функции testInsertUser.Я присоединяю недавно созданный ArrayList объектов PlayedTile к этой доске, а затем выполняю вспомогательный метод DataMaster.saveUser, который использует диспетчер персистентности Google App Engine для сохранения пользователя (и, следовательно, коллекции Board и PlayedTile) в хранилище данных.В следующем методе мы пытаемся загрузить этого пользователя (с его коллекцией Board и PlayedTile) и отобразить сохраненные результаты.Последует хаос.
Вот код JUnit:
package com.astar.wordswall.test.data;
import java.util.ArrayList;
import com.astar.wordswall.data.DataMaster;
import com.astar.wordswall.data.jdo.Board;
import com.astar.wordswall.data.jdo.User;
import com.astar.wordswall.data.jdo.PlayedTile;
import com.astar.wordswall.test.appengine.LocalCustomHighRepPolicy;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
// import com.google.gwt.user.client.Random;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class SaveUsersBoardWithTilesTest {
Key userKey;
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setAlternateHighRepJobPolicyClass(LocalCustomHighRepPolicy.class));
@Before
public void setUp() {
helper.setUp();
}
@After
public void tearDown() {
helper.tearDown();
}
@Test
public void testInsert1() {
testInsertUser();
testReadUser();
}
/**
* Creation and insertion of a user, board, and linked set of tiles into BigTable.
*/
private void testInsertUser() {
User u = new User("Simon");
Board b = new Board();
ArrayList<PlayedTile> tiles = new ArrayList<PlayedTile>(7);
u.setBoard(b);
b.setPlayedTiles(tiles);
for (int j = 0; j < 7; j++) tiles.add(new PlayedTile('T'));
DataMaster.saveUser(u);
// Retrieve the user's key so that we can read him from the database later
userKey = u.getUserKey();
// Display all of our saved tiles:
System.out.println("Saved tiles:");
// Note that "getTileString()" just iterates through each Played tile printing the letter
System.out.println("\t" + u.getBoard().getTileString());
}
/**
* A typical read of a user object from the Datastore.
*/
private void testReadUser() {
User u = DataMaster.getUserWithBoard(userKey);
// Display all of our saved tiles:
System.out.println("Loaded tiles:");
System.out.println("\t" + u.getBoard().getTileString());
}
}
А вот соответствующая статическая функция DataMaster.getUserWithBoard, которая фактически выполняет загрузку JDO:
/**
* Loads a uniquely specified User and their associated board from
* the Datastore. It also loads the board's complete list of PlayedTiles.
* @param userKey the unique key assigned to this user
*/
public static User getUserWithBoard(Key userKey){
User u = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try{
u = pm.getObjectById(User.class, userKey);
// In order for the board and tile collection to load, we must "touch" it while PM is active
if (u.getBoard().getPlayedTiles().size() != 0) u.getBoard().getPlayedTiles().get(0);
if (u.getBoard().getPlayedWords().size() != 0) u.getBoard().getPlayedWords().get(0);
} finally{
pm.close();
}
return u;
}
Страннодостаточно, этот код SOMETIMES работает должным образом: он печатает тот же набор плиток, который он сохраняет после загрузки их из хранилища данных в testReadUser ().ИНОГДА он просто загружает пустую коллекцию, хотя особенно странно то, что вызов u.getBoard (). GetPlayedWords (). Get (0) не вызывает исключение нулевого указателя.
Выход колеблется между
Правильно:
Saved tiles:
T T T T T T T
Loaded tiles:
T T T T T T T
И неверно:
Saved tiles:
T T T T T T T
Loaded tiles:
совершенно беспорядочно.
Может кто-нибудьтам пролить свет на это?Это сводит меня с ума.:)
EDIT : Еще одна странная подсказка / факт: если я сделаю весь тест повторяющимся, включив вызовы методов testSaveUser и testReadUser в цикл for, либо КАЖДЫЕ операции загрузки выполняются правильноили никто из них не делает.Это ошибка в локальной тестовой среде Google App Engine?