JPA关联两张表失败:idsubscriber字段多可写映射异常
问题解决:JPA关联字段重复映射错误
错误原因
错误提示说得很清楚:subscriber.idsubscriber字段有多个可写映射。你在Subscriber类里犯了个典型错误——同时把这个字段做了两件事:
- 单独映射成普通的实体属性(带
@Column注解) - 又把它作为
@OneToOne关联的外键(@JoinColumn)
JPA不允许同一个数据库字段被多个可写映射绑定,不然持久化时会搞不清该用哪个值更新字段。
修复步骤
1. 修正Subscriber类的映射
直接删掉重复的idsubscriber普通属性映射就行,或者如果非要保留这个属性的读取功能,就把它标记为只读。推荐优先保留关联映射,通过关联对象访问字段:
修改后的Subscriber关键代码:
@Entity @Table(name = "subscriber") @XmlRootElement // 省略NamedQueries部分 public class Subscriber implements Serializable { // 省略其他属性... // 删掉原来的idsubscriber普通属性 // @Basic(optional = false) // @Column(name = "idsubscriber", nullable = false, length = 50) // private String idsubscriber; @OneToOne(targetEntity = Deon.class, cascade = CascadeType.ALL) @JoinColumn(name = "idsubscriber", referencedColumnName = "idsubscriber") private Deon deon; // 顺便把getItems/setItems改个合理的名字,和属性名对应上: public Deon getDeon() { return deon; } public void setDeon(Deon deon) { this.deon = deon; } // 省略其他方法... }
如果非要保留idsubscriber属性的读取,就把它改成只读:
@Column(name = "idsubscriber", insertable = false, updatable = false) private String idsubscriber;
2. 修正Main类的JPQL错误
你的JPQL有俩问题:
- 属性名大小写错了:
s.Deon要写成s.deon(Java属性名是小写的) - 查询返回的是
Object[]数组(存的是name和price两个值),不是Subscriber对象,强转会直接报错
修改后的Main代码:
// 查name和price的写法 List<Object[]> resultList = em.createQuery("SELECT s.name, d.price FROM Subscriber s JOIN s.deon d").getResultList(); for (Object[] row : resultList) { String name = (String) row[0]; Integer price = (Integer) row[1]; System.out.println(name + " -- " + price); }
如果要查完整的Subscriber并关联Deon,用FETCH JOIN:
List<Subscriber> ll = em.createQuery("SELECT s FROM Subscriber s JOIN FETCH s.deon d").getResultList(); for (Subscriber f : ll) { System.out.println(f.getName() + " -- " + f.getDeon().getPrice()); }
3. 可选:加双向关联(如果需要)
要是需要从Deon反向查Subscriber,就在Deon类里加对应注解:
@Entity @Table(name = "deon", catalog = "mngp", schema = "") // 省略其他部分 public class Deon implements Serializable { // 省略其他属性... @OneToOne(mappedBy = "deon") private Subscriber subscriber; // 加getter和setter public Subscriber getSubscriber() { return subscriber; } public void setSubscriber(Subscriber subscriber) { this.subscriber = subscriber; } // 省略其他方法... }
总结
核心就是解决同一个数据库字段的重复可写映射问题,要么删重复属性,要么标记为只读。另外注意JPQL的语法细节,别搞混属性大小写和查询结果类型。
内容的提问来源于stack exchange,提问作者Adm
相关产品推荐
相关产品推荐

