Удаление сирот после замены родителя в отношениях один ко многим

Я упорствую School лица в хранилище данных с PersistenceManager, School имеет отношения один ко многим с Student s:

@PersistenceCapable
public class School implements Serializable {
    ...
    @Persistent(mappedBy = "school") @Element(dependent = "true") private Set<Student> students = new HashSet<Student>();
    ...
    @PrimaryKey private String key;

    School(String name, Level level) {
        this.name = Objects.requireNonNull(name);
        this.level = Objects.requireNonNull(level);
        this.key = name + "_" + level;
    }
    ...
}

@PersistenceCapable
public class Student implements Serializable {
    ...
    @PrimaryKey private Key key;

    Student(String name, School school, int grade) {
        this.name = Objects.requireNonNull(name);
        this.grade = Objects.requireNonNull(grade);
        this.school = Objects.requireNonNull(school);
        key = KeyFactory.createKey(this.school.getKey(), this.getClass().getSimpleName(), name + "_" + grade + "_" + school.getName());
    }
    ...
}

Скажи, я сохраняю School с несколькими Student s:

School school = new School("foo", Level.MIDDLE);
Student s1 = new Student("A", school, 6);
Student s2 = new Student("B", school, 6);
Student s3 = new Student("C", school, 6);
school.addStudent(s1);
school.addStudent(s2);
school.addStudent(s3);
PMF.get().getPersistenceManager().makePersistent(school);

Потом,

School school = new School("foo", Level.MIDDLE); // Will have the same primary key as the first!
Student s1 = new Student("A", school, 6);
Student s2 = new Student("B", school, 6);
Student s3 = new Student("D", school, 6); // Note the change! C -> D
// Some code that makes s1 and s2 different from their previous state
school.addStudent(s1);
school.addStudent(s2);
school.addStudent(s3);
PMF.get().getPersistenceManager().makePersistent(school);

Так как School будет иметь то же самое PrimaryKey каждый раз (а именно "foo_middle"), вторая постоянная операция перезаписывает первую. Там будет только 1 школа фу.

К счастью, обновленные версии Student A и Student B заменили свои старые аналоги в хранилище данных, поскольку их первичные ключи были равны. Тем не менее, будет 4 Student сущности в хранилище данных, так как студент C не был уничтожен. Это несоответствие становится актуальным с одной конкретной точки зрения на мое заявление. Как мне наиболее эффективно избавиться от этого ребенка-сироты?

Вот что я пробовал / рассматривал:

  1. Явно удалить все School объекты (эта операция будет каскадно и уничтожит все Student s) также до добавления нового набора, вместо того, чтобы позволить GAE обрабатывать замену. Это проблематично, потому что (1) стоимость выше с точки зрения чтения / записи (2) удаление и повторное добавление должны быть независимыми, а одно следует строго за другим, поэтому новые School также не удаляются. Вероятно, это может быть достигнуто с помощью транзакций?
  2. Явное удаление всех осиротевших Student запрашивая их перед сохранением второго School и сверяя их с school.getStudents(), Этот подход связан с высокой стоимостью и добавляет много сложности.

Другой возможностью было бы спроектировать объекты таким образом, чтобы я мог запрашивать все Student s, которые не были осиротевшими. Тогда я мог бы удалять сирот с фиксированными интервалами только для того, чтобы сохранить расходы на хранение низкими. Тем не менее, я не вижу, как достичь такого результата при сохранении School с и Student s, которые заменяют старый экземпляр, когда сохраняются (имея тот же первичный ключ).

1 ответ

Причина, по которой студент "C" не умирает, в том, что вы просто переопределяете foo_middle, а не уничтожаете его. БД работает так: когда обнаруживается дубликат идентификатора, он переопределяет существующий. Вы видите это, когда добавляете ученика "А" и "В". БД не убивает ни один из оригиналов, просто заменяет остальные данные (кроме идентификатора). У вас есть 2 варианта в зависимости от вашего варианта использования:

1) Если вы удаляете менее половины, вы можете добавить поле добавления / обновления даты, после обновления вы просто делаете запрос для всех тех, у кого дата до текущей, а затем удаляете их.

2) Если вы удалите более половины, сделайте запрос предка, затем очистите всех учеников.

Другие вопросы по тегам