与Play框架2.3.8中的Ebeans的OneToOne关系

时间:2015-11-18 07:21:46

标签: playframework yaml playframework-2.3 ebean

请原谅我,如果这是微不足道的 - 白天我是C#/ .NET后端工程师,不熟悉Play Framework和EBean,以及所有其他与此环境相关的事情。

我使用内存H2数据库和javax.persistence库来管理我的业务层/持久层。我有三个实体(课程,学生,成绩单),我已经定义并试图通过使用带有初始数据的yaml文件来播种。

到目前为止,我已设法创建,持久化并检索课程与学生之间的ManyToMany关系。

但是,我在学生和成绩单之间创建OneToOne关系时遇到了麻烦。在使用初始数据为db播种之后,我尝试通过查找例如

来检索Student或Transcript对象
FIND.where().eq(ID, id).findUnique()

对另一个对象的引用为null(Transcript对象对其Student属性具有空引用,Student对象对其Transcript属性具有空引用)。

当我保存到数据库时,看起来学生似乎有对Transcript的引用(参见下面的Global.java),就在单步执行调试器并检查属性时。

这是学生实体(请注意@OneToOne transcript属性):

@Entity
@Table(name="students")
public class Student extends Model {

    private static final String ID = "id";

    @Id
    @Constraints.Required
    @Formats.NonEmpty
    public String id;

    @Constraints.Required
    public String username;

    @Constraints.Required
    public String password;

    @Constraints.Required
    public String fullname;

    @Constraints.Required
    @ManyToMany
    public List<Course> coursesPreferred = new ArrayList<Course>();

    @Constraints.Required
    public int numCoursesPreferred;

    @Constraints.Required
    @OneToOne
    public Transcript transcript;

    // -- Queries

    private static final Model.Finder<String, Student> FIND =
            new Model.Finder<>(String.class, Student.class);

    /**
     * Returns all students.
     */
    public static List<Student> findAll() {
        return FIND.all();
    }

    /**
     * Returns the student with the given ID.
     *
     * @param id student ID
     */
    public static Student findById(String id) {

        return FIND.where().eq(ID, id).findUnique();
    }

    // --

    public String toString() {
        return "Student{" + fullname + "}";
    }

}

这里是Transcript实体(注意@OneToOne学生属性,由成绩单映射):

@Entity
@Table(name="transcripts")
public class Transcript extends Model {

    private static final String ID = "id";

    @Id
    @Constraints.Required
    @Formats.NonEmpty
    public String id;

    @Constraints.Required
    @OneToOne(mappedBy="transcript")
    public Student student;

    @Constraints.Required
    public int creditsEarned;

    // -- Queries

    private static final Model.Finder<String, Transcript> FIND =
            new Model.Finder<>(String.class, Transcript.class);

    /**
     * Returns all transcripts.
     */
    public static List<Transcript> findAll() {
        return FIND.all();
    }

    /**
     * Returns the transcript with the given ID.
     *
     * @param id transcript ID
     */
    public static Transcript findById(String id) {
        return FIND.where().eq(ID, id).findUnique();
    }

    // --

   public String toString() {
        return "Transcript{" + id + "}";
    }

}

以下是包含初始数据的yaml文件:

# Courses

courses:

    - &course6476 !!models.Course
        id:         6476
        tag:        "CS 6476"
        name:       "Computer Vision"
        abbrev:     "CV"
        core:       Yes

    - &course6035 !!models.Course
        id:         6035
        tag:        "CS 6035"
        name:       "Introduction to Information Security"
        abbrev:     "IIS"
        core:       No

    - &course6210 !!models.Course
        id:         6210
        tag:        "CS 6210"
        name:       "Advanced Operating Systems"
        abbrev:     "AOS"
        core:       Yes

# Transcripts

transcripts:

    - &transcript0001 !!models.Transcript
        id:         0001
        creditsEarned: 42

# Students

students:

    - &student0001 !!models.Student
        id:         0001
        username:   "joeschmoe"
        password:   "password1234"
        fullname:   "Joe Schmoe"
        numCoursesPreferred: 2
        coursesPreferred:
            - *course6210
            - *course6035
        transcript: *transcript0001 

最后,这里是Global.java文件,其中读入并保存数据:

public class Global extends GlobalSettings {

    private static final String INITIAL_DATA_FILE = "initial-data.yml";
    private static final String COURSES = "courses";
    private static final String STUDENTS = "students";
    private static final String TRANSCRIPTS = "transcripts";

    @Override
    public void onStart(Application app) {
        InitialData.insert(app);
    }

    private static class InitialData {
        private static void insert(Application app) {
            if (Student.findAll().size() == 0) {
                Map<String, List<?>> all =
                        (Map<String, List<?>>)     Yaml.load(INITIAL_DATA_FILE);

                Ebean.save(all.get(COURSES));
                Ebean.save(all.get(TRANSCRIPTS));
                Ebean.save(all.get(STUDENTS));
            }
        }
    }
}

我在这里可能缺少什么想法?我是否需要更改指定OneToOne关系的方式?调试/故障排除的其他步骤?任何信息都值得赞赏,因为我碰到了一堵砖墙。

提前非常感谢!

1 个答案:

答案 0 :(得分:1)

我弄明白了这个问题。无法检索OneToOne属性值的查询是:

FIND.where().eq(ID, id).findUnique();

因此,例如,这将返回一个Student,其中包含Student.transcript属性的有效Transcript引用,但该Transcript引用的所有属性都为null或默认值,例如: creditsEarned = 0而不是42,就像它应该基于我的种子数据一样。

看来为了检索缺失值,您必须在查询中明确“获取”它们。因此,对于ID的学生查询,它变为:

FIND.fetch("transcript").where().eq(ID, id).findUnique();

这将返回完全填充的Student,包括所有Transcript值。我读到设置@OneToOne(fetch = FetchType.EAGER)应该自动执行此操作,但我在一些来源中发现EBeans不支持@OneToOne的fetch参数。