Почему моя собственная связь «один ко многим» не сохраняется в хранилище данных GAE?

У меня есть два класса, определенных и сопоставленных с хранилищем данных GAE — класс Person и класс LocationStamp, которые представляют одну комбинацию широты/долготы вместе с отметкой времени. Существует собственное сопоставление "один ко многим" между Person и LocationStamp, реализованное в строках, аналогичных сообщение на форуме об отношениях "один ко многим".

В моем DAO для Person у меня есть следующий метод:

   public LocationStamp addLocationStampForCurrentUser(LocationStamp ls)
   {
      PersistenceManager pm = getPersistenceManager();

      Person p = getProfileForCurrentUser();
      p.getLocationStamps().add(ls);

      pm.currentTransaction().begin();
      try {
         pm.makePersistent(p);
         pm.currentTransaction().commit();
         return ls;
      } finally {
         if (pm.currentTransaction().isActive()) {
            pm.currentTransaction().rollback();
         }
         pm.close();
      }
   }    

Когда я пытаюсь использовать этот метод для добавления записи в коллекцию объекта из LocationStamp сущностей, связь не сохраняется. Более поздний запрос для соответствующего объекта Person возвращает правильный объект с адресом электронной почты, но список locationStamps пуст. Кроме того, средство просмотра данных для сервера App Engine не показывает никаких объектов LocationStamp (и в таблице для Person нет ни одного столбца для locationStamps.

Я внимательно следовал инструкциям в сообщении на форуме, но я не уверен, что что-то упустил.

Вот мои сущности:

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class Person
{

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

   @Persistent
   private String emailAddress;

   @Persistent
   private String name;

   @Persistent(mappedBy = "person")
   @Element(dependent = "true")
   @Order(extensions = @Extension(vendorName = "datanucleus", key = "list-ordering", value = "timestamp desc"))
   private final List<LocationStamp> locationStamps = new ArrayList<LocationStamp>();

   // ... getters and setters ...
}

а также

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
public class LocationStamp
{

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

   @Persistent
   private double latitude;

   @Persistent
   private double longitude;

   @Persistent
   private Date timestamp;

   @Persistent
   private boolean automatic;

   @Persistent
   private Person person;

   // ... getters and setters ...
}

Поскольку они используются в приведенном выше коде, вот определения для нескольких других методов:

   public Person getProfileForCurrentUser()
   {
      PersistenceManager pm = getPersistenceManager();
      try {
         Key k = getKeyForEmailAddress(getCurrentUserEmail());
         return pm.getObjectById(Person.class, k);
      } catch (JDOObjectNotFoundException e) {
         // Create a new profile if the new one isn't found
         return updateProfileForCurrentUser(new Person());
      } finally {
         pm.close();
      }
   }

   public Person updateProfileForCurrentUser(Person p)
   {
      p.setEmailAddress(getCurrentUserEmail());
      return update(p);
   }

   public Person update(Person p)
   {
      PersistenceManager pm = getPersistenceManager();
      try {
         pm.currentTransaction().begin();
         Key k = getKeyForEmailAddress(p.getEmailAddress());
         p.setKey(k);
         pm.makePersistent(p);
         pm.currentTransaction().commit();
         return p;
      } finally {
         if (pm.currentTransaction().isActive()) {
            pm.currentTransaction().rollback();
         }
         pm.close();
      }
   }

   private Key getKeyForEmailAddress(String emailAddress)
   {
      return KeyFactory.createKey(Person.class.getSimpleName(), emailAddress);
   }

   private static PersistenceManager getPersistenceManager()
   {
      // PMF is a singleton class that returns an instance of PersistenceManagerFactory
      return PMF.get().getPersistenceManager();
   }

person Milind Ganjoo    schedule 16.01.2012    source источник


Ответы (1)


Когда у вас есть список в объекте Persistence, загрузка списка является ленивой операцией. Поэтому, если вы закроете PersistenceManager перед загрузкой списка, список не будет загружен.

Попробуйте использовать:

public Person getProfileForCurrentUser()
{
    PersistenceManager pm = getPersistenceManager();
    try {
        Key k = getKeyForEmailAddress(getCurrentUserEmail());
        Person p = pm.getObjectById(Person.class, k);
        p.getLocationStamps().size();
        return p;
    } catch (JDOObjectNotFoundException e) {
        // Create a new profile if the new one isn't found
        return updateProfileForCurrentUser(new Person());
    } finally {
        pm.close();
    }
}
person Victor    schedule 16.01.2012
comment
Превосходно. Я думал, что избавился от всех проблем с ленивой загрузкой, когда следовал инструкциям на форуме, но мне явно нужно было явно загрузить список. - person Milind Ganjoo; 17.01.2012