【问题标题】:Removing orphans after replacing parent in a one-to-many relationship在一对多关系中替换父级后删除孤儿
【发布时间】:2014-10-15 15:56:29
【问题描述】:

我使用PersistenceManagerSchool 实体保存到数据存储区。 SchoolStudents 是一对多的关系:

@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 和几个Students:

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 School foo

幸运的是,Student AStudent B 的更新版本已经替换了数据存储区中的旧版本,因为它们的主键相同。但是,由于Student C未销毁,数据存储区中将有 4Student 实体。这种不一致在我的应用程序的一个特定视图中变得相关。我怎样才能最有效地摆脱这个孤儿?

这是我尝试/考虑过的:

  1. 在添加新集合之前明确删除所有School 实体(此操作将cascade 并销毁它拥有的所有Students),而不是让GAE 处理替换。这是有问题的,因为 (1) 在读/写方面的成本更高 (2) 删除和重新添加需要保持独立,一个紧接着一个,所以新的Schools 不会得到也被删除了。这大概可以通过交易来实现?
  2. 通过在持久化第二个School 之前查询它们并根据school.getStudents() 检查它们来显式删除所有孤立的Student。这种方法的成本很高,并且会增加很多复杂性。

另一种可能性是以我可以查询所有未孤立的Students 的方式设计对象。然后我可以以固定的时间间隔删除孤儿,只是为了降低存储成本。但是,我不知道如何在保持Schools 和Students 的同时实现这样的结果,它们在持久化时替换旧实例(通过具有相同的主键)。

【问题讨论】:

    标签: java google-app-engine transactions google-cloud-datastore jdo


    【解决方案1】:

    学生'C'没有死的原因是你只是覆盖了 foo_middle 而不是破坏它。数据库的工作方式是当发现重复 ID 时,它会覆盖现有 ID。当您添加学生“A”和“B”时,您会看到这一点。数据库不会杀死任何原始数据,只是替换其余数据(ID 除外)。根据您的用例,您有 2 个选项:

    1) 如果您删除的时间少于一半,您可以添加添加/更新日期字段,在更新后您只需查询所有日期早于当前日期的人,然后删除这些人。

    2) 如果您要删除一半以上的祖先查询,则刷新所有学生。

    【讨论】:

    • 是的,我明白为什么它们没有被删除。您的选项 2 与我的选项 1 相同。您的选项 1 是我将探索的一种可能性......除非我弄错了,否则它需要在每个 Student 中都有一个日期字段,因为我觉得这很令人反感m 修改 Student 的定义,使其更适合数据库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-24
    • 2010-10-18
    • 1970-01-01
    • 2013-06-05
    • 2012-08-16
    相关资源
    最近更新 更多