【问题标题】:JPA 2.0 Simple @OneToOne mapping fails on insertJPA 2.0 简单 @OneToOne 映射在插入时失败
【发布时间】:2013-02-04 22:11:16
【问题描述】:

我正在尝试创建一个简单的 JPA 2.0 风格的单向映射。对象模型很简单

一个用户可以有一个地址。

@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;
}



}

这就是我试图创建一个新用户并为该用户设置地址的操作。

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();
 }

这是我得到的错误 -

[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)

这个错误是非常基本的,并指出地址记录上没有设置用户 ID 值。似乎这里的持久性管理器有足够的信息来完成这个简单的事务。映射出了什么问题?

【问题讨论】:

  • 所以显然持久性管理器不喜欢从子表映射到相应对象的外键。由于关系是单向的,它只强制从父到子的可导航性。因此,让外键不暴露在孩子身上将确保没有办法在没有父母的情况下直接找到和/或导航孩子。所以在上面的例子中,只需要删除 @Column(name="userid") private long userId; public long getUserId() { return userId; } public void setUserId(long userId) { this.userId = userId; }
  • 好的,删除它可以让我通过插入,但它实际上没有用。 user_id 不会保留在地址表中。所以实际上这是一个空值。

标签: jpa jpa-2.0 eclipselink


【解决方案1】:

地址具有您未设置的用户 ID。除非您要设置从地址到用户的一对一关系映射,否则它需要手动设置为用户 ID。使用映射 userid 字段的连接列设置 onetoone,并标记 user->address 已被新关系映射。示例见http://www.eclipse.org/eclipselink/api/2.0/javax/persistence/OneToOne.html

【讨论】:

  • 无法在此上下文中设置 UserId。由于尚未分配,因此始终为空。
  • 要么持久化并刷新用户以获取分配的 ID,您可以将其用于该字段,或者将类型从 long 更改为 Long,以便可以插入 null 直到您可以设置它。但是该字段由地址的用户标识属性控制,这就是插入 0 的原因。您需要从地址到用户的映射,以便提供商为您设置值。
  • 是的,这行得通。然而,模型本身是有缺陷的。像这样的 OneToOne 关系从未真正在数据库级别强制执行。你确实回答了提出的问题,所以我必须给你。
【解决方案2】:

我做错的是定义允许 OneToMany 的关系,但试图将其建模为 OneToOne 关系。

我应该在 User 表上有一个 address_id 列,而不是在 address 表上有一个 user_id。如果我在 User 表上定义 address_id 列并像这样映射我的实体

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

它工作得很好。这是持久性管理器期望定义的 OneToOne 关系的方式。

【讨论】:

    猜你喜欢
    • 2014-05-17
    • 2012-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-16
    • 1970-01-01
    • 2020-08-20
    • 1970-01-01
    相关资源
    最近更新 更多