user1796571
user1796571

Reputation: 772

JPA 2.0 Simple @OneToOne mapping fails on insert

I am trying to create a simple JPA 2.0 style unidirectional mapping. The object model is simple

One User can have One Address.

@Entity
@Table(name = "USERS")
public class User {

@Id
@SequenceGenerator(name="user_seq",sequenceName = "sequence",allocationSize=1) 
@GeneratedValue (generator="user_seq",strategy=GenerationType.SEQUENCE)
@Column(name="userid")
private Long userId;

@Column(name="emailid")
private String emailId;

@OneToOne(cascade=CascadeType.PERSIST)
@PrimaryKeyJoinColumn
private Address address;

public User() {

}

public Long getUserId() {
    return userId;
}

public void setUserId(Long userId) {
    this.userId = userId;
}


public String getEmailId() {
    return emailId;
}

public void setEmailId(String emailId) {
    this.emailId = emailId;
}


public Address getAddress() {
    return address;
}

public void setAddress(Address address) {
    this.address = address;
}


}

@Entity
@Table(name="address")
public class Address {
@Id
@SequenceGenerator(name="address_seq",sequenceName =               "hibernate_sequence",allocationSize=1) 
@GeneratedValue (generator="address_seq",strategy=GenerationType.SEQUENCE)
private long id;


@Column(name="userid")
private long userId;

@Column(name="address")
private String completeAddress;



public Address() {
    super();
}



public Address (String completeAddress) {
    super();
    this.completeAddress = completeAddress;
}



public long getId() {
    return id;
}

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

public long getUserId() {
    return userId;
}

public void setUserId(long userId) {
    this.userId = userId;
}

public String getCompleteAddress() {
    return completeAddress;
}

public void setCompleteAddress(String completeAddress) {
    this.completeAddress = completeAddress;
}



}

This is what I am trying to execute to create a new user and set the address on that user.

EntityManager em = entityManagerFactory.createEntityManager();
 EntityTransaction tx = em.getTransaction();
 try {
     tx.begin();
     User user = new User();
     user.setEmailId("test123");
     Address address = new Address();
     address.setCompleteAddress("some address");
     user.setAddress(address);
     em.persist(user);
     tx.commit();
 } catch (Exception e) {
     em.getTransaction().rollback();
 } finally {
     em.close();
 }

This is the error I get -

[EL Warning]: 2013-02-04 16:00:03.376--UnitOfWork(1827795025)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: insert or update on table "address" violates foreign key constraint "address_userid_fkey"
  Detail: Key (userid)=(0) is not present in table "users".
  Error Code: 0
  Call: INSERT INTO address (ID, userid, address) VALUES (?, ?, ?)
bind => [43, 0, some address]
  Query: InsertObjectQuery(com.jpa.test.Address@5c001eb0)

The error is very basic and states that the userid value is not getting set on the address record. Seems like there is enough information for the persistence manager here to make this simple transaction happen. What has gone wrong in the mapping?

Upvotes: 1

Views: 2445

Answers (2)

user1796571
user1796571

Reputation: 772

What I was doing wrong was defining the relationship that allowed for OneToMany but trying to model it as a OneToOne relationship.

I should have a address_id column on the User table and not a user_id on the address table. If I define the address_id column on the User table and map my entity like this

@OneToOne(cascade=CascadeType.PERSIST)
@JoinColumn(name="address_id")
//@PrimaryKeyJoinColumn
private Address address; 

it works just fine. This is the way the persistence manager is expecting a OneToOne relationship defined.

Upvotes: 0

Chris
Chris

Reputation: 21165

Address has userid which you are not setting. It needs to be set to user's id manually unless you are going to set a one to one relation mapping from Address to User. Set up a onetoone with a join column mapping the userid field, and mark the user->address was mappedby the new relation. See http://www.eclipse.org/eclipselink/api/2.0/javax/persistence/OneToOne.html for examples

Upvotes: 1

Related Questions