简体   繁体   中英

Why Hibernate need to recreate other entries in unidirectional ManyToMany when using List

The entities (using Set):

@Entity
class Product(
    @Id
    @GeneratedValue
    val int: Int = 0,
    val name : String,
    @ManyToMany(cascade = [(CascadeType.PERSIST), (CascadeType.MERGE)])
    val stores:  MutableSet<Store> = mutableSetOf()
)

@Entity
class Store(
        @Id
        @GeneratedValue
        val int: Int = 0,
        val name : String = ""
)

...

val p = Product(name = "product")
        em.persist(p)
        val store = Store(name = "store");
        p.stores += store
        em.persist(store)
        for (i in 1..5) {
            val s = Store(name = i.toString())
            p.stores += s
            em.persist(s)
        }
        em.flush()
        p.stores.remove(store)
        em.flush()

The result:

Hibernate: insert into product (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: delete from product_stores where product_int=? and stores_int=?

But with this entity (using List):

@Entity
class Product(
    @Id
    @GeneratedValue
    val int: Int = 0,
    val name : String,
    @ManyToMany(cascade = [(CascadeType.PERSIST), (CascadeType.MERGE)])
    val stores:  MutableList<Store> = mutableListOf()
)

The result:

Hibernate: insert into product (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into store (name, int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: delete from product_stores where product_int=?
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)
Hibernate: insert into product_stores (product_int, stores_int) values (?, ?)

From Hibernate User Guide: http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#associations-many-to-many

When an entity is removed from the @ManyToMany collection, Hibernate simply deletes the joining record in the link table. Unfortunately, this operation requires removing all entries associated with a given parent and recreating the ones that are listed in the current running persistent context.

But I don't know the reason behind it, why can't we just do the same as in the Set case

The @ManyToMany annotation with a List is telling hibernate to expect a joinTable without index

List that don't use index column in one-to-many relation are treated implicitly as bags and this lead to

https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/performance-collections.html

Bags are the worst case. Since a bag permits duplicate element values and has no index column, no primary key may be defined. Hibernate has no way of distinguishing between duplicate rows. Hibernate resolves this problem by completely removing (in a single DELETE) and recreating the collection whenever it changes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM