Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OneToOne relationship for a non primary key column

I'm having a problem when I query an entity who has a OneToOne relationship with another one. This is the scenario:

Database tables:

create table people (
    id decimal(10,0) NOT NULL,
    email varchar(512) NOT NULL
);

create table users (
    email varchar(512) NOT NULL
);

Test data:

insert into users (email) values ('[email protected]');
insert into users (email) values ('[email protected]');

insert into people (id, email) values (1, '[email protected]');
insert into people (id, email) values (2, '[email protected]');

Entities:

@Entity(name = "people")
public class Person implements Serializable {

    @Column
    @Id
    private long id;

    @Column
    private String email;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

}

@Entity(name = "tbl_users")
public class User implements Serializable {

    @Id
    private String email;

    @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name = "email", referencedColumnName = "email")
    private Person person;

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Invocation:

...
User user = entityManager.find(User.class, "[email protected]");
...

After de invocation, the hibernate's logs shows:

select user1_.email as email2_0_, person2_.id as id1_1_, person2_.email as email1_1_
from users user1_ left outer join people person2_ on user1_.email=person2_.id
where user1_.email=?

As you can see, the join is wrong because is comparing users.email with people.id (user1_.email=person2_.id), so it returns an User without its corresponding Person.

Any ideas about how can I fix it?

Thanks a lot !!

like image 209
RDV Avatar asked Nov 18 '13 06:11

RDV


2 Answers

Strictly speaking, the JPA specification does not allow references to non-primary key columns. It may work in some JPA implementations, but it's not proper.

However, i think you can do this by making the relationship bidirectional, and owned by the side with the non-primary key:

@Entity
public class Person {

    @Id
    private long id;

    @OneToOne
    @JoinColumn(name = "email")
    private User user;

    public String getEmail() {
        return user.getEmail();
    }

    public void setEmail(String email) {
        // left as an exercise for the reader
    }

}

@Entity
public class User {

    @Id
    private String email;

    @OneToOne(mappedBy = "user")
    private Person person;

}

I haven't actually tried that, though, so caveat hackor.

like image 101
Tom Anderson Avatar answered Nov 02 '22 03:11

Tom Anderson


I think you should rethink your datamodel. The relationship between User and Person looks more like one of Inheritance.

For the issue with your mappings as they stand see here for some further disussion:

JPA providers: why do relationships/FKs to non-PK columns work in Hibernate and EclipseLink?

Does the JPA specification allow references to non-primary key columns?

like image 20
Alan Hay Avatar answered Nov 02 '22 04:11

Alan Hay