Java 休眠与同一实体的递归多对多关联
另一个冬眠问题…:P 使用Hibernate的注释框架,我有一个Java 休眠与同一实体的递归多对多关联,java,hibernate,jakarta-ee,entity-relationship,hibernate-annotations,Java,Hibernate,Jakarta Ee,Entity Relationship,Hibernate Annotations,另一个冬眠问题…:P 使用Hibernate的注释框架,我有一个用户实体。每个用户都可以拥有一组朋友:一组其他用户s。但是,我还没有弄清楚如何在User类中创建多对多关联,该类由Users列表组成(使用User-friends中间表) 以下是用户类及其注释: @Entity @Table(name="tbl_users") public class User { @Id @GeneratedValue @Column(name="uid") private In
用户
实体。每个用户
都可以拥有一组朋友:一组其他用户
s。但是,我还没有弄清楚如何在User
类中创建多对多关联,该类由User
s列表组成(使用User-friends中间表)
以下是用户类及其注释:
@Entity
@Table(name="tbl_users")
public class User {
@Id
@GeneratedValue
@Column(name="uid")
private Integer uid;
...
@ManyToMany(
cascade={CascadeType.PERSIST, CascadeType.MERGE},
targetEntity=org.beans.User.class
)
@JoinTable(
name="tbl_friends",
joinColumns=@JoinColumn(name="personId"),
inverseJoinColumns=@JoinColumn(name="friendId")
)
private List<User> friends;
}
@实体
@表(name=“tbl\U用户”)
公共类用户{
@身份证
@生成值
@列(name=“uid”)
私有整数uid;
...
@许多(
cascade={CascadeType.PERSIST,CascadeType.MERGE},
targetEntity=org.beans.User.class
)
@可接合(
name=“tbl_朋友”,
joinColumns=@JoinColumn(name=“personId”),
inverseJoinColumns=@JoinColumn(name=“friendId”)
)
私人名单朋友;
}
用户好友映射表只有两列,这两列都是tbl_users
表的uid
列的外键。这两列是personId
(应该映射到当前用户)和friendId
(指定当前用户朋友的id)
问题是,“friends”字段一直为空,即使我已经预先填充了friends表,使得系统中的所有用户都是其他所有用户的朋友。我甚至尝试过将关系切换到@OneToMany
,结果仍然为空(尽管Hibernate调试输出显示了一个SELECT*,来自tbl_friends,其中personId=?和friendId=?
查询,但没有其他内容)
关于如何填充此列表,有什么想法吗?谢谢大家! @ManyToMany to self相当令人困惑,因为您通常建模的方式不同于“休眠”方式。你的问题是你错过了另一个收藏 这样想吧——如果你将“作者”/“书”映射为多对多,你需要书上的“作者”集合和作者上的“书籍”集合。在这种情况下,“用户”实体表示关系的两端;因此,您需要“我的朋友”和“我的朋友”系列:
@ManyToMany
@JoinTable(name="tbl_friends",
joinColumns=@JoinColumn(name="personId"),
inverseJoinColumns=@JoinColumn(name="friendId")
)
private List<User> friends;
@ManyToMany
@JoinTable(name="tbl_friends",
joinColumns=@JoinColumn(name="friendId"),
inverseJoinColumns=@JoinColumn(name="personId")
)
private List<User> friendOf;
@manytomy
@JoinTable(name=“tbl_friends”,
joinColumns=@JoinColumn(name=“personId”),
inverseJoinColumns=@JoinColumn(name=“friendId”)
)
私人名单朋友;
@许多
@JoinTable(name=“tbl_friends”,
joinColumns=@JoinColumn(name=“friendId”),
inverseJoinColumns=@JoinColumn(name=“personId”)
)
私人名单;
您仍然可以使用相同的关联表,但请注意,join/inverseJon列在集合上交换
“friends”和“friendOf”集合可能匹配,也可能不匹配(取决于您的“friendOf”是否始终是相互的),当然,您不必在API中以这种方式公开它们,但这是在Hibernate中映射它们的方法。实际上,这非常简单,可以通过以下方式实现,比如说您有以下实体
public class Human {
int id;
short age;
String name;
List<Human> relatives;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public short getAge() {
return age;
}
public void setAge(short age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Human> getRelatives() {
return relatives;
}
public void setRelatives(List<Human> relatives) {
this.relatives = relatives;
}
public void addRelative(Human relative){
if(relatives == null)
relatives = new ArrayList<Human>();
relatives.add(relative);
}
}
对于
@JoinTable
注释,公认的答案似乎过于复杂。稍微简单一点的实现只需要一个mappedBy
。使用mappedBy
表示拥有的实体或财产,这可能是对的引用,因为这将被视为“朋友”。一个manytomy
关系可以创建一个非常复杂的图形。使用mappedBy
使代码如下:
@Entity
public class Recursion {
@Id @GeneratedValue
private Integer id;
// what entities does this entity reference?
@ManyToMany
private Set<Recursion> referencesTo;
// what entities is this entity referenced from?
@ManyToMany(mappedBy="referencesTo")
private Set<Recursion> referencesFrom;
public Recursion init() {
referencesTo = new HashSet<>();
return this;
}
// getters, setters
}
这将提供以下日志输出(始终检查生成的SQL语句):
我希望你能第三次来救我:)它工作得很好,你的解释大大澄清了我对E-R的理解。再次非常感谢您!:)我可以把friends和friendOf结合起来吗?如果没有,那么我就需要在一个实体中使用jsonmanagedreference和jsonbackreference来解决这个问题:我使用Hibernate 5,一个集合就足够了-使用两个集合会在tbl_friends中创建重复的行。我怎么能在“tbl_friends”中同时使用“friendId”和“personId”有唯一的约束呢?我认为值得补充一下,如果使用相同的表,其中一个表应该有一个“mappedBy”,而不是@JoinTable
。friendOf例如:@ManyToMany(mappedBy=“friends”)
。否则,hibernate将尝试同时保留这两个项,并导致java.sql.SQLIntegrityConstraintViolationException:key“PRIMARY”的重复条目“x-y”
import org.junit.Test;
import org.know.common.HBUtil;
import org.know.july31.hb.Human;
public class SimpleTest {
@Test
public void test() {
Human h1 = new Human();
short s = 23;
h1.setAge(s);
h1.setName("Ratnesh Kumar singh");
Human h2 = new Human();
h2.setAge(s);
h2.setName("Praveen Kumar singh");
h1.addRelative(h2);
Human h3 = new Human();
h3.setAge(s);
h3.setName("Sumit Kumar singh");
h2.addRelative(h3);
Human dk = new Human();
dk.setAge(s);
dk.setName("D Kumar singh");
h3.addRelative(dk);
HBUtil.getSessionFactory().getCurrentSession().beginTransaction();
HBUtil.getSessionFactory().getCurrentSession().save(h1);
HBUtil.getSessionFactory().getCurrentSession().getTransaction().commit();
HBUtil.getSessionFactory().getCurrentSession().beginTransaction();
h1 = (Human)HBUtil.getSessionFactory().getCurrentSession().load(Human.class, 1);
System.out.println(h1.getRelatives().get(0).getName());
HBUtil.shutdown();
}
}
@Entity
public class Recursion {
@Id @GeneratedValue
private Integer id;
// what entities does this entity reference?
@ManyToMany
private Set<Recursion> referencesTo;
// what entities is this entity referenced from?
@ManyToMany(mappedBy="referencesTo")
private Set<Recursion> referencesFrom;
public Recursion init() {
referencesTo = new HashSet<>();
return this;
}
// getters, setters
}
tx.begin();
Recursion r0 = new Recursion().init();
Recursion r1 = new Recursion().init();
Recursion r2 = new Recursion().init();
r0.getReferencesTo().add(r1);
r1.getReferencesTo().add(r2);
em.persist(r0);
em.persist(r1);
em.persist(r2);
tx.commit();
// required so that existing entities with null referencesFrom will be removed from cache.
em.clear();
for ( int i=1; i <= 3; ++i ) {
Recursion r = em.createQuery("select distinct r from Recursion r left join fetch r.referencesTo left join fetch r.referencesFrom where id = :id", Recursion.class).setParameter("id", i).getSingleResult();
System.out.println(r + " To=" + Arrays.toString(r.getReferencesTo().toArray()) + " From=" + Arrays.toString(r.getReferencesFrom().toArray()) );
}
tx.begin();
em.createQuery("delete from Recursion where id = 2").executeUpdate();
tx.commit();
// required so that existing entities with referencesTo will be removed from cache.
em.clear();
Recursion r = em.createQuery("select distinct r from Recursion r left join fetch r.referencesTo left join fetch r.referencesFrom where id = :id", Recursion.class).setParameter("id", 1).getSingleResult();
System.out.println(r + " To=" + Arrays.toString(r.getReferencesTo().toArray()) + " From=" + Arrays.toString(r.getReferencesFrom().toArray()) );
Hibernate: create table Recursion (id integer not null, primary key (id))
Hibernate: create table Recursion_Recursion (referencesFrom_id integer not null, referencesTo_id integer not null, primary key (referencesFrom_id, referencesTo_id))
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: alter table Recursion_Recursion add constraint FKsi0wfuwfs0bl19jjpofw4n8pt foreign key (referencesTo_id) references Recursion
Hibernate: alter table Recursion_Recursion add constraint FKarrkuyh2v1j5qnlui2vbpl7tk foreign key (referencesFrom_id) references Recursion
Hibernate: call next value for hibernate_sequence
Hibernate: call next value for hibernate_sequence
Hibernate: call next value for hibernate_sequence
Hibernate: insert into Recursion (id) values (?)
Hibernate: insert into Recursion (id) values (?)
Hibernate: insert into Recursion (id) values (?)
Hibernate: insert into Recursion_Recursion (referencesFrom_id, referencesTo_id) values (?, ?)
Hibernate: insert into Recursion_Recursion (referencesFrom_id, referencesTo_id) values (?, ?)
Hibernate: select distinct recursion0_.id as id1_2_0_, recursion2_.id as id1_2_1_, recursion4_.id as id1_2_2_, references1_.referencesFrom_id as referenc1_3_0__, references1_.referencesTo_id as referenc2_3_0__, references3_.referencesTo_id as referenc2_3_1__, references3_.referencesFrom_id as referenc1_3_1__ from Recursion recursion0_ left outer join Recursion_Recursion references1_ on recursion0_.id=references1_.referencesFrom_id left outer join Recursion recursion2_ on references1_.referencesTo_id=recursion2_.id left outer join Recursion_Recursion references3_ on recursion0_.id=references3_.referencesTo_id left outer join Recursion recursion4_ on references3_.referencesFrom_id=recursion4_.id where id=?
model.Recursion@7bdf6bb7 To=[model.Recursion@1bc53649] From=[]
Hibernate: select distinct recursion0_.id as id1_2_0_, recursion2_.id as id1_2_1_, recursion4_.id as id1_2_2_, references1_.referencesFrom_id as referenc1_3_0__, references1_.referencesTo_id as referenc2_3_0__, references3_.referencesTo_id as referenc2_3_1__, references3_.referencesFrom_id as referenc1_3_1__ from Recursion recursion0_ left outer join Recursion_Recursion references1_ on recursion0_.id=references1_.referencesFrom_id left outer join Recursion recursion2_ on references1_.referencesTo_id=recursion2_.id left outer join Recursion_Recursion references3_ on recursion0_.id=references3_.referencesTo_id left outer join Recursion recursion4_ on references3_.referencesFrom_id=recursion4_.id where id=?
model.Recursion@1bc53649 To=[model.Recursion@42deb43a] From=[model.Recursion@7bdf6bb7]
Hibernate: select distinct recursion0_.id as id1_2_0_, recursion2_.id as id1_2_1_, recursion4_.id as id1_2_2_, references1_.referencesFrom_id as referenc1_3_0__, references1_.referencesTo_id as referenc2_3_0__, references3_.referencesTo_id as referenc2_3_1__, references3_.referencesFrom_id as referenc1_3_1__ from Recursion recursion0_ left outer join Recursion_Recursion references1_ on recursion0_.id=references1_.referencesFrom_id left outer join Recursion recursion2_ on references1_.referencesTo_id=recursion2_.id left outer join Recursion_Recursion references3_ on recursion0_.id=references3_.referencesTo_id left outer join Recursion recursion4_ on references3_.referencesFrom_id=recursion4_.id where id=?
model.Recursion@42deb43a To=[] From=[model.Recursion@1bc53649]
Hibernate: delete from Recursion_Recursion where (referencesTo_id) in (select id from Recursion where id=2)
Hibernate: delete from Recursion_Recursion where (referencesFrom_id) in (select id from Recursion where id=2)
Hibernate: delete from Recursion where id=2
Hibernate: select distinct recursion0_.id as id1_2_0_, recursion2_.id as id1_2_1_, recursion4_.id as id1_2_2_, references1_.referencesFrom_id as referenc1_3_0__, references1_.referencesTo_id as referenc2_3_0__, references3_.referencesTo_id as referenc2_3_1__, references3_.referencesFrom_id as referenc1_3_1__ from Recursion recursion0_ left outer join Recursion_Recursion references1_ on recursion0_.id=references1_.referencesFrom_id left outer join Recursion recursion2_ on references1_.referencesTo_id=recursion2_.id left outer join Recursion_Recursion references3_ on recursion0_.id=references3_.referencesTo_id left outer join Recursion recursion4_ on references3_.referencesFrom_id=recursion4_.id where id=?
model.Recursion@6b739528 To=[] From=[]