[英]Understand OneToMany Relationship in JPA
我在一对多关系中有两个实体:
父实体:
@Entity
@Table(name = "PIANOTAGLIE")
public class PianoTaglia {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String pianoTaglia;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "pianoTaglia", cascade = CascadeType.ALL)
private List<Taglia> taglie;
public PianoTaglia() {
}
[...] Getter/Setter [...]
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PianoTaglia other = (PianoTaglia) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
和子实体:
@Entity
@Table(name = "TAGLIE")
public class Taglia {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 10, unique = true)
private String taglia;
@ManyToOne
private PianoTaglia pianoTaglia;
public Taglia() {
}
[...] Getter/Setter [...]
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Taglia other = (Taglia) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
为了管理我的实体,我使用以下通用Dao:
public abstract class JpaDAO<E> {
protected Class<E> entityClass;
@PersistenceContext(unitName = "PrudiPU")
protected EntityManager em;
@SuppressWarnings("unchecked")
public JpaDAO() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
this.entityClass = (Class<E>) genericSuperclass.getActualTypeArguments()[0];
}
public List<E> findAll() {
TypedQuery<E> q = em.createQuery("SELECT h FROM " + entityClass.getName() + " h", entityClass);
return q.getResultList();
}
public void persist(E entity) {
em.persist(entity);
}
public E getReference(Long id) {
return em.getReference(entityClass, id);
}
}
专门针对每个班级(这是PianoTagliaDao,但TagliaDao相同)
@Repository
public class PianoTaglieDao extends JpaDAO<PianoTaglia> {
}
创建PianoTaglia时,我会使用生成的ID保留对对象的引用...这样我就可以浏览应用程序,并随时可以创建Taglia。 当我创建Taglia时,我以这种方式使用对PianoTaglia的引用,该引用是先前创建的:
PianoTaglia pt = getPreviuslyCreatedPianoTaglia(); //this is an example
Taglia tg = new Taglia();
tg.setTaglia("XXL");
tg.setPianoTaglia(pt);
pt.getTaglie().add(tg);
taglieDao.persist(tg);
taglieDao.flush(); //i need to flush for keep generated ID
[...]
如果我将表检查到DB都可以! 所有的桌子都装满了! 但是,如果我尝试获取所有PianoTaglia,则taglie集合始终为空:
List<PianoTaglia> pianoTagle = pianoTagliaDao.findAll();
for(PianoTaglia pt : pianoTaglie) {
assert pt.getTaglie().isEmpty();
}
经过测试后,我找到了解决方案:创建taglia时,我必须保留PianoTaglie的新引用:
PianoTaglia old = getPreviuslyCreatedPianoTaglia();
PianoTaglia pt = pianoTaglieDao.getReference(old.getId()); //getReference call the namesake method in the EntityManager
Taglia tg = new Taglia();
tg.setTaglia("XXL");
tg.setPianoTaglia(pt);
pt.getTaglie().add(tg);
taglieDao.persist(tg);
taglieDao.flush(); //i need to flush for keep generated ID
[...]
这样,当我保留PianoTaglia对象时,就很好地填充了taglie集合。
我的问题是:为什么JPA会有这种行为?
看起来您正在存储先前创建的PianoTaglia,并在上下文关闭后将其保留良好,因此持久性单元将其视为不受管理的。 非托管实体不会被跟踪,因此所做的任何更改都不会反映在数据库中。 这意味着pt.getTaglie()。add(tg); 代码没有在entityManager知道的事情上完成。
通过使用getReference或find api,您将检索实体的托管实例,以便EntityManager可以跟踪对其所做的任何更改。 您也可以替换getReference和pianoTaglieDao.persist(tg);。 行带有pianoTaglieDao.merge(old)调用,它将对旧PianoTaglia所做的更改合并回持久性单元。 最好使用getReference或查找而不是缓存非托管实体,以帮助减少陈旧数据的覆盖,这可能更好。 缓存的对象可能不会反映最新的更改,然后可能会被合并调用覆盖,并且为了提高性能,它使您以后可以将应用程序扩展到多个线程和服务器,而无需进行大量更改。
您好,我不确定您在数据库中有哪些字段,但尝试添加
@JoinColumn("user_id")
下一行
@ManyToOne
private PianoTaglia pianoTaglia;
结果将是
@ManyToOne
@JoinColumn("pianoTagliaId")
private PianoTaglia pianoTaglia;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.