Java Spring JPA:重用属性存储另一个对象时,数据库中未存储多个关系
如果必须持久化对象的“复杂”结构,那么@manytomy关联就有问题 我有一个Java应用程序使用SpringBoot(SpringBootStarterParent2.2.5.RELEASE)和JPA(SpringBootStarterDataJPA)。作为一个数据库,我尝试了MySQL和H2。效果是一样的 摘要1 我在创建类别时使用列表对象,在创建项目对象时使用相同的列表对象Java Spring JPA:重用属性存储另一个对象时,数据库中未存储多个关系,java,spring-data-jpa,Java,Spring Data Jpa,如果必须持久化对象的“复杂”结构,那么@manytomy关联就有问题 我有一个Java应用程序使用SpringBoot(SpringBootStarterParent2.2.5.RELEASE)和JPA(SpringBootStarterDataJPA)。作为一个数据库,我尝试了MySQL和H2。效果是一样的 摘要1 我在创建类别时使用列表对象,在创建项目对象时使用相同的列表对象 Category cat1 = new Category("Cat 1", personList
Category cat1 = new Category("Cat 1", personList, null);
categoryService.create(cat1);
Item item1 = new Item("Item 1", personList, cat1);
itemService.create(item1);
Category cat2 = new Category("Cat 2", personList, null);
categoryService.create(cat2);
Item item2 = new Item("Item 2", cat2.getManagers(), cat2);
itemService.create(item2);
- 类别记录在类别管理器表中有三个人被指定为经理
- 项目记录中有三条人员记录被指定为项目人员表中的人员
Category cat1 = new Category("Cat 1", personList, null);
categoryService.create(cat1);
Item item1 = new Item("Item 1", personList, cat1);
itemService.create(item1);
Category cat2 = new Category("Cat 2", personList, null);
categoryService.create(cat2);
Item item2 = new Item("Item 2", cat2.getManagers(), cat2);
itemService.create(item2);
- 在item_persons表中,该项有三条指定为人员的人员记录
- !!!该类别在“类别管理者”表中没有管理者分配
Category cat3 = new Category("Cat 3", personList, null);
categoryService.create(cat3);
cat3.setManagers(personList);
categoryService.update(cat3);
Item item3 = new Item("Item 3", cat3.getManagers(), cat3);
itemService.create(item3);
- 该类别有三个人记录被指定为经理(请参见.category\u managers表)
- 该项目有三个指定为人员的人员记录(参见项目\人员表)
我没有考虑什么吗?
我是否误解了幕后发生的事情 这可能是一个特殊的用例,但是否有一些主题或章节我必须再次阅读 斯图加特的问候
详细说明 模型结构 Person.java:
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
// Constructors -------------------------------------------------------------------------------
public Person() {}
public Person(String firstName, String lastName) {
super();
this.firstName = firstName;
this.lastName = lastName;
}
// Getters / Setters --------------------------------------------------------------------------
// ...
}
Category.java:
@Entity
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany
private List<Person> managers;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name="category_id", updatable = false)
private List<Item> items;
// Constructors -------------------------------------------------------------------------------
public Category() {}
public Category(String name, List<Person> managers, List<Item> items) {
super();
this.name = name;
this.managers = managers;
this.items = items;
}
// Getters / Setters --------------------------------------------------------------------------
// ...
}
三个测试用例
这里有一段代码来演示我在数据库中创建记录时面临的问题。
有3例
@Component
public class DatabaseInitializer implements CommandLineRunner {
@Autowired
CategoryService categoryService;
@Autowired
ItemService itemService;
@Autowired
PersonService personService;
@Override
public void run(String... args) throws Exception {
// Create persons
Person max = personService.create(new Person("Max", "Mad"));
Person sally = personService.create(new Person("Sally", "Silly"));
Person bob = personService.create(new Person("Bob", "Bad"));
List<Person> personList = Arrays.asList(max, sally, bob);
// Case 1 (this works)
// Here we will use the personList object for both the category and the item.
Category cat1 = new Category("Cat 1", personList, null);
categoryService.create(cat1);
Item item1 = new Item("Item 1", personList, cat1);
itemService.create(item1);
// => The category record has three person records assigned as managers (see. category_managers table)
// => The item record has three person records assigned as persons (see. item_persons table)
// Case 2 (this doesn't work)
// Here we will use the personList object to create the category and reuse the category.getManager list to create the item.
Category cat2 = new Category("Cat 2", personList, null);
categoryService.create(cat2);
Item item2 = new Item("Item 2", cat2.getManagers(), cat2);
itemService.create(item2);
// => The category has no managers assignments (see. category_managers table) WHY??
// => The item has three person records assigned as persons (see. item_persons table)
// Case 3 (workaround of case 2)
// Here we will do the same as in case 2, but will do an extra assignment of the managers of the category
Category cat3 = new Category("Cat 3", personList, null);
categoryService.create(cat3);
cat3.setManagers(personList);
categoryService.update(cat3);
Item item3 = new Item("Item 3", cat3.getManagers(), cat3);
itemService.create(item3);
// => The category has three person records assigned as managers (see. category_managers table)
// => The item has three person records assigned as persons (see. item_persons table)
}
}
@组件
公共类数据库初始值设定项实现CommandLineRunner{
@自动连线
类别服务类别服务;
@自动连线
项目服务项目服务;
@自动连线
人情服务人情服务;
@凌驾
公共无效运行(字符串…参数)引发异常{
//造人
personmax=personService.create(新人物(“max”、“Mad”);
personsally=personService.create(新人物(“sally”、“傻瓜”);
personbob=personService.create(新人物(“bob”、“Bad”);
List personList=Arrays.asList(max、sally、bob);
//案例1(本工程)
//这里我们将对类别和项目使用personList对象。
类别cat1=新类别(“类别1”,个人列表,空);
categoryService.create(cat1);
项目1=新项目(“项目1”,个人列表,类别1);
itemService.create(item1);
//=>类别记录中有三个人记录被分配为经理(请参见.category\u managers表)
//=>项目记录有三个人记录被分配为人员(请参见项目人员表)
//案例2(这不起作用)
//在这里,我们将使用personList对象来创建类别,并重用category.getManager列表来创建项目。
类别cat2=新类别(“类别2”,个人列表,空);
categoryService.create(cat2);
Item item2=新项(“Item 2”,cat2.getManagers(),cat2);
itemService.create(item2);
//=>该类别没有经理分配(请参见.category\u managers表)为什么??
//=>该项目有三条指定为人员的人员记录(请参见.item\u persons表)
//案例3(案例2的变通方法)
//在这里,我们将执行与案例2中相同的操作,但将对该类别的经理进行额外的分配
类别cat3=新类别(“类别3”,个人列表,空);
categoryService.create(cat3);
cat3.设置经理(个人列表);
类别服务更新(cat3);
Item item3=新项目(“Item 3”,cat3.getManagers(),cat3);
itemService.create(item3);
//=>该类别有三个人记录被指定为经理(请参见.category\u managers表)
//=>该项目有三条指定为人员的人员记录(请参见.item\u persons表)
}
}
我将直接进入案例2。它不起作用,因为它不在事务中。创建实体时:新类别(“类别2”,个人列表,空)代码>该实体已分离。然后调用事务方法categoryService.create(cat2)代码>并将其交给类别。在事务中,实体将被持久化,并且试图让管理者工作,但是一旦事务完成,数据库更新,我们将返回run()
方法我们不再在该事务中。实体cat2是在该事务之外创建的,并且在事务完成后不会更新。如果您希望能够使用相同的方法访问cat2.getManagers()
,我建议将run()
方法设置为事务性的。尝试解释案例2
调用JpaRepository
或crudepository
的方法save(S entity)
时,对象cat2
的属性managers
的ArrayList对象将变为PersistentBag对象。现在,这个集合对象不仅仅包含Person
对象的实体。它还表示实体类别
和个人
之间的关系
还要记住:Java对象变量指向内存堆中的对象。
因此,在Item item2=new Item(“Item 2”,cat2.getManagers()行中,
Category cat3 = new Category("Cat 3", personList);
categoryService.create(cat3);
personList.add(personService.create(new Person("Mazy", "Lazy")));
cat3.setManagers(personList);
categoryService.update(cat3);
Item item3 = new Item("Item 3", cat3.getManagers(), cat3);
itemService.create(item3);
Category cat2 = new Category("Cat 2", personList);
categoryService.create(cat2);
List<Person> itemPersonList = new ArrayList<>();
cat2.getManagers().forEach(itemPersonList::add);
Item item2 = new Item("Item 2", itemPersonList, cat2);
itemService.create(item2);