我有一个名为Player的父实体和两个名为bat和ball的子实体。
玩家实体的PK为"playerId",球的复合pk是"playerId(FK("one_answers"ballColor",&蝙蝠的复合pk是"playerId(FK("one_answers"batColor">
注:球员对击球是OneToOne,球员对球是OneToMany(单向(
@Entity
@Table(name = "player")
public class Player implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "player_id")
private Long playerId;
@JsonManagedReference
@OneToMany(mappedBy = "player", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@Fetch(value=FetchMode.SELECT)
private List<Ball> balls;
@OneToOne(mappedBy = "player", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JsonManagedReference
private Bat bat;
// getters and setters
}
@Entity
@Table(name = "bat")
public class Bat implements Serializable {
private static final long serialVersionUID = -114046508592L;
@EmbeddedId
private BatEmbeddedId batEmbeddedId = new BatEmbeddedId();
@MapsId("playerId")
@OneToOne
@JoinColumn(name = "bat_id", insertable = false, updatable = false)
@JsonBackReference
private Player player;
// getters and setters for player field
}
@Entity
@Table(name = "ball")
public class Ball implements Serializable {
private static final long serialVersionUID = -1108592L;
@EmbeddedId
private BallEmbeddedId ballEmbeddedId = new BallEmbeddedId();
@MapsId("playerId")
@ManyToOne
@JoinColumn(name = "ball_id", insertable = false, updatable = false)
@JsonBackReference
private Player player;
// getters and setters for player field
}
@Embeddable
public class BatEmbeddedId implements Serializable{
private static final long serialVersionUID = -91976886L;
@Column(name = "player_id")
private Long playerId;
@Column(name = "bat_color")
private String batColor;
public BatEmbeddedId() {}
public BatEmbeddedId(Long playerId, String batColor) {
super();
this.playerId= playerId;
this.batColor= batColor;
}
// getters and setters for all fields
}
@Embeddable
public class BallEmbeddedId implements Serializable{
private static final long serialVersionUID = -91976889990L;
@Column(name = "player_id")
private Long playerId;
@Column(name = "ball_color")
private String ballColor;
public BatEmbeddedId() {}
public BatEmbeddedId(Long playerId, String ballColor) {
super();
this.playerId= playerId;
this.ballColor= ballColor;
}
// getters and setters for all fields
}
public interface PlayerRepository extends JpaRepository<Player, Long>, JpaSpecificationExecutor<Player> {
Player findByPlayerId(Long playerId);
}
@Service
public class myService{
@Autowired
PlayerRepository playerRepository;
// Save logic for player
Player player = new Player();
BatEmbeddedId batEmId = new BatEmbeddedId();
//note i can't set the playerId here coz its not yet generated
batEmId.setBatColor("white");
Bat bat = new Bat();
bat.setBatEmbeddedId(batEmId);
bat.setPlayer(player);
player.setBat(bat); // added bat to player object
List<Ball> balls = new ArrayList<>();
BallEmbeddedId ballEmId1 = new BallEmbeddedId();
BallEmbeddedId ballEmId2 = new BallEmbeddedId();
ballEmId1.setBallColor("white");
ballEmId2.setBallColor("red");
Ball b1 = new Ball();
Ball b2 = new Ball();
b1.setBallEmbeddedId(ballEmId1);
b2.setBallEmbeddedId(ballEmId2);
balls.add(b1);
balls.add(b2);
//adding balls to player object
player.setBalls(balls);
//finally calling a save
playerRepository.save(player);
}
运行以上代码后,我得到以下错误:org.springframework.dao.DataIntegrityViolationException: A different object with the same identifier value was already associated with the session
我是否在这些相关实体的保存逻辑中做错了什么?
非常感谢!!!
尝试如下更正映射:
@Entity
@Table(name = "bat")
public class Bat implements Serializable {
// ...
@EmbeddedId
private BatEmbeddedId batEmbeddedId = new BatEmbeddedId();
@MapsId("playerId")
@OneToOne
@JoinColumn(name = "player_id")
@JsonBackReference
private Player player;
// getters and setters for player field
}
@Embeddable
public class BatEmbeddedId implements Serializable{
// ...
// @Column annotation will be ignored as you use @MapsId("playerId")
// The column name will be taken from the @JoinColumn(name = "player_id") annotation
// @Column(name = "player_id")
private Long playerId;
@Column(name = "bat_color")
private String batColor;
public BatEmbeddedId() {}
public BatEmbeddedId(Long playerId, String batColor) {
// super() is redundant
// super();
this.playerId= playerId;
this.batColor= batColor;
}
// getters and setters for all fields
// The primary key class must define equals and hashCode methods,
// consistent with equality for the underlying database types to which the primary key is mapped.
// see https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#identifiers-composite
@Override
public boolean equals(Object o) {
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
BatEmbeddedId pk = (BatEmbeddedId) o;
return Objects.equals( playerId, pk.playerId ) &&
Objects.equals( batColor, pk.batColor );
}
@Override
public int hashCode() {
return Objects.hash( playerId, batColor );
}
}
@Entity
@Table(name = "ball")
public class Ball implements Serializable {
// ...
@EmbeddedId
private BallEmbeddedId ballEmbeddedId = new BallEmbeddedId();
@MapsId("playerId")
@ManyToOne
@JoinColumn(name = "player_id")
@JsonBackReference
private Player player;
// getters and setters for player field
}
@Embeddable
public class BallEmbeddedId implements Serializable{
// ...
// @Column(name = "player_id")
private Long playerId;
@Column(name = "ball_color")
private String ballColor;
public BatEmbeddedId() {}
public BatEmbeddedId(Long playerId, String ballColor) {
this.playerId= playerId;
this.ballColor= ballColor;
}
// getters and setters for all fields
// equals and hashCode
}
您是否已经尝试从玩家协会中删除insertable = false, updatable = false
?@MapsId
应该能够在没有这种情况下进行处理。此外,您应该将可嵌入类型中的列标记为nullable = false
。
如果问题仍然存在,你确定你没有在同一事务中做任何其他事情吗?
您使用的是最新的Hibernate 5.4.29版本吗?如果是,并且您仍然有问题,请在问题跟踪器中创建一个问题(https://hibernate.atlassian.net)带有测试用例(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java)它再现了这个问题。