views:

36

answers:

1

Hello,

I'm having a problem modelling the following problem in JPA. I have a JPA Entity class 'User', like so: (accessors/mutators/extraneous fields/extraneous JPA configuration omitted for brevity)


    @Entity
    class User {
        @Id
        @Generated Value
        long id;
        @OneToMany
        Report contributorReports; // All the reports where this user is contributor
        @OneToMany ownerReports; // All the reports where this user is owner
        String username;
    }

and a JPA Entity class 'Report'


@Entity
class Report {
    @Id
    @GeneratedValue
    long id;
    @OneToOne
    User contributor;
    @OneToOne
    User owner;
    SomeData data;
}

I would like to model a relationship such that:

  • A Report must contain both a contributor and an owner
  • I can access all of the Reports a User has been a 'contributor' for via the User Entity
  • I can access all of the Reports a User has been a 'owner' for via the User Entity

I imagined I would end up with a mapping table that looked vaguely like this:


CREATE TABLE user_report {
    BIGINT reportId,
    BIGINT contributorId,
    BIGINT ownerId,
}

I attempted to solve the problem like:


    @OneToOne
    @JoinTable(name = "user_report",
            joinColumns = {
                    @JoinColumn(name = "reportOwner_ID", referencedColumnName = "ID")}
            )
    private User owner;
    @OneToOne
    @JoinTable(name = "user_report",
            joinColumns = {
                @JoinColumn(name = "reportContributor_ID", referencedColumnName = "ID")}
            )
    private User contributor;

This generates a table like:

CREATE TABLE user_report (
    BIGINT ownerReport_ID, // Report ID
    BIGINT reportOwner_ID, // UserID owner
    BIGINT contributorReport_ID, // Report ID
    BIGINT reportContributor_ID // UserID contributor
)

So when JPA attempts to map to this table, it maps each field separately and fails because only half of the row is being committed, throwing this exception:

Caused by: java.sql.BatchUpdateException: Field 'ownerReport_ID' doesn't have a default value

I was hoping to get some direction on how to best model the relationship I envision. (Or maybe a better way to envision the relationship) If additional information is needed, I'll be glad to provide it.

Kind Regards Matt

+2  A: 

Based on your requirements I believe you accomplish this with 2 1:M from User to Report with a matched M:1 back for each.

@Entity
class User {
    @Id
    @Generated Value
    long id;

    // All the reports where this user is contributor
    @OneToMany(mappedBy="contributor")
    List<Report> contributorReports; 

    // All the reports where this user is owner
    @OneToMany(mappedBy="owner")
    List<Report> ownerReports; 

    String username;
}

Then your Report class would look like:

@Entity
class Report {
    @Id
    @GeneratedValue
    long id;

    @ManyToOne
    User contributor;

    @ManyToOne
    User owner;

    SomeData data;
}

This situation is also possible with a join table but not required based on your requirements as I understand them.

Doug

Doug Clarke
Thanks Doug, that was indeed exactly what I needed! Forest for the trees and all that.
Matt