Я использую springboot (2.1.9.RELEASE) и hibernate (5.4.6.Final) для разработки программы, и мне нужно lazyload поля типа String (changelog), поэтому я использую PersistentAttribute Interceptable, поля типа строкиможет быть ленивая загрузка, но таблица соединения ManyToMany не работает. Вот код
@Entity
@Table(name = "categories")
public class Category implements Serializable {
private static final long serialVersionUID = 911243379555328411L;
@Id
@Column(name = "id")
private Long id;
private String name;
private int position;
@ManyToOne
@JoinColumn(name = "parent_id")
private Category parent;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@OrderColumn(name = "position")
List<Category> children;
@ManyToMany(mappedBy = "categories")
private Set<Item> items;
// getter AND setter
}
@Entity
@Table(name = "items")
public class Item implements Serializable, PersistentAttributeInterceptable {
private static final long serialVersionUID = 6129011836002505114L;
@Id
@Column(name = "id")
private Long id;
@Column(name = "table_name")
private String table;
@Column(name = "description")
private String description;
@Lob
@Basic(fetch = FetchType.LAZY)
private String changelog;
@ManyToMany
@JoinTable(name = "category_items", joinColumns = @JoinColumn(name = "item_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "category_id", referencedColumnName = "id"))
private Set<Category> categories;
@Transient
private PersistentAttributeInterceptor interceptor;
// id, table, description getter setter
public String getChangelog() {
if (interceptor != null) {
return (String) interceptor.readObject(this, "changelog", changelog);
}
return null;
}
public void setChangelog(String changelog) {
if (changelog == null) {
if (interceptor != null) {
interceptor.writeObject(this, "changelog", this.changelog, changelog);
return;
}
}
this.changelog = changelog;
}
public Set<Category> getCategories() {
if (null == categories) {
categories = new HashSet<>();
}
if (interceptor != null) {
return (Set<Category>) interceptor.readObject(this, "categories", categories);
}
return categories;
}
public void setCategories(Set<Category> categories) {
if (categories == null) {
if (interceptor != null) {
interceptor.writeObject(this, "categories", this.categories, categories);
return;
}
}
this.categories = categories;
}
@Override
public PersistentAttributeInterceptor $$_hibernate_getInterceptor() {
return interceptor;
}
@Override
public void $$_hibernate_setInterceptor(PersistentAttributeInterceptor persistentAttributeInterceptor) {
interceptor = persistentAttributeInterceptor;
}
}
Код тестового примера
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ItemRepositoryTest {
@Autowired ItemRepository itemRepository;
@Autowired CategoryRepository categoryRepository;
@Transactional
@Rollback(false)
@Test
public void save() {
Category root = buildCategory(1L, "root", 0);
Category child1 = buildCategory(2L, "child1", 1);
Category child2 = buildCategory(3L, "child2", 2);
Category child3 = buildCategory(4L, "child3", 3);
List<Category> children = Arrays.asList(child1, child2, child3);
root.setChildren(children);
List<Category> categories1 = Arrays.asList(root, child1, child2, child3);
categoryRepository.saveAll(categories1);
categoryRepository.flush();
Item item = buildItem(1L, "SecuMain", "test");
Set<Category> categories = new HashSet<>();
categories.add(child1);
item.setCategories(categories);
itemRepository.saveAndFlush(item);
assertTrue(true);
}
}
После выполнения тестового примера данные были вставлены в категориии таблица элементов, но у joinTable category_items нет данных. Если Item не использует PersistentAttributeAttributeable, данные могут быть записаны в таблицу элементов категории, но журнал изменений не может быть загружен с отложенной загрузкой.