JPA Spring boot将新的子级附加到多个关系中的现有实体
在我看来,我发现jpa有一种奇怪的行为。首先,这里是我的代码的简化版本(如果我遗漏了什么,请告诉我) 所以现在我从Rest接口获取数据,以添加一个可能有名称的新子级JPA Spring boot将新的子级附加到多个关系中的现有实体,spring,spring-boot,jpa,Spring,Spring Boot,Jpa,在我看来,我发现jpa有一种奇怪的行为。首先,这里是我的代码的简化版本(如果我遗漏了什么,请告诉我) 所以现在我从Rest接口获取数据,以添加一个可能有名称的新子级 @Autowired ChildRpo childRepo; @Autowired ParentRepo parentRepo; @PostMapping("/example/{parentName}/{childName}") public void add(@PathVar("parentNam
@Autowired
ChildRpo childRepo;
@Autowired
ParentRepo parentRepo;
@PostMapping("/example/{parentName}/{childName}")
public void add(@PathVar("parentName") String pName,
@PathVar("childName") String cName) {
// Here is the Problem I think
Parent p = parentRepo.findByName(pName).get();
p.getChilds.add(new Child(cName,p);
this.parentRepo.save(p);
}
案例1:pName=pa2&cName=child3(按预期工作)
案例2:pName=pa2&cName=child1(与我预期的不完全一样),但情况如何
| Parent | | parent_child_mapping | | Child |
| id | name | | child_id | parent_id | | id | name |
| 1 | pa1 | | 1 | 1 | | 1 | child1 |
| 2 | pa2 | | 2 | 1 | | 2 | child2 |
| 3 | 2 | | 3 | child1 |
案例3:pName=pa2&cName=child1我期望的是什么,但事实并非如此
| Parent | | parent_child_mapping | | Child |
| id | name | | child_id | parent_id | | id | name |
| 1 | pa1 | | 1 | 1 | | 1 | child1 |
| 2 | pa2 | | 2 | 1 | | 2 | child2 |
| 1 | 2 |
我必须解决以下问题:
我认为unique属性使列唯一,因此具有相同内容的两个字符串不能同时存在于此行“name”中,但它可以工作。我希望在案例2中出现例外情况
第二个:
我如何配置它,使其像我希望的那样工作?
我必须加载childOne的id吗?并将它们附加到新的child1实体?
我想,因为这个领域是独一无二的,spring可以决定:
该字段不在列中,因此我添加了一个新的子字段。
该字段位于列中,因此我不会创建新的子项,而是将父项附加到具有相同名称的旧子项。-但默认情况下,这不是它的工作方式——有没有一种方式可以像上面描述的那样工作
附言:
以下是当前代码中的域模型:
Book -- oneToMany --> Page -- oneToMany --> Version -- ManyToOne --> Author
Book -- oneToMany --> Locations
..
如何在不加载所有关系的情况下向id=5的页面和id=4的作者添加“Quick”新版本
编辑:数据库由hibernate创建,以下是属性:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto= update
@列中的Unique属性才起作用。如果可能,让提供商重新创建数据库。您可以从属性中执行此操作
spring.jpa.hibernate.ddl auto=createdrop
Parent p = parentRepo.findByName(pName).get();
Child newChild;
Optional<Child> result = childRpo.findByName(cName);
if(result != null) {
newChild = result.get();
}
else {
newChild = new Child(cName);
}
p.getChilds.add(newChild);
newChild.getParents().add(p);
parentRepo.save(p);
Parent p=parentRepo.findByName(pName.get();
儿童-新生儿;
可选结果=childRpo.findByName(cName);
如果(结果!=null){
newChild=result.get();
}
否则{
newChild=新子(cName);
}
p、 getChilds.add(newChild);
newChild.getParents().add(p);
父母储蓄(p);
@列中的Unique属性才起作用。如果可能,让提供商重新创建数据库。您可以从属性中执行此操作
spring.jpa.hibernate.ddl auto=createdrop
Parent p = parentRepo.findByName(pName).get();
Child newChild;
Optional<Child> result = childRpo.findByName(cName);
if(result != null) {
newChild = result.get();
}
else {
newChild = new Child(cName);
}
p.getChilds.add(newChild);
newChild.getParents().add(p);
parentRepo.save(p);
Parent p=parentRepo.findByName(pName.get();
儿童-新生儿;
可选结果=childRpo.findByName(cName);
如果(结果!=null){
newChild=result.get();
}
否则{
newChild=新子(cName);
}
p、 getChilds.add(newChild);
newChild.getParents().add(p);
父母储蓄(p);
这些表是手动创建的还是由hibernate创建的?您的问题肯定缺少详细信息,如
p.getChilds.add(new Child(cName));
不会对数据库做任何事情。如果您的示例应用程序具有Parent
和Child
实体,您可以在注释中提供链接并在本地复制它。您是对的。我编辑的帖子不正确。您必须建立双向关系。Child newChild=newChild(cName);p.getChilds.add();newChild.setParent(p);this.parentRepo.save(p);
同样,你是对的,我在孩子的构造函数中添加了缺少的关系作为功能。我可以通过frandpaste.com共享它们,但如果你想“工作”实体我认为您需要所有这些。这将是七个实体和七个回购。我将为您提供链接。这里有一个指向从实体到控制器的所有类的链接:您是手动创建表还是由hibernate创建的?您的问题肯定缺少详细信息,如p.getChilds.add(new Child(cName));
不会对数据库做任何事情。如果您的示例应用程序具有Parent
和Child
实体,您可以在注释中提供链接并在本地复制它。您是对的。我编辑的帖子不正确。您必须建立双向关系。Child newChild=newChild(cName);p.getChilds.add();newChild.setParent(p);this.parentRepo.save(p);
同样,你是对的,我在孩子的构造函数中添加了缺少的关系作为功能。我可以通过frandpaste.com共享它们,但如果你想“工作”实体我认为你需要所有这些。这将是七个实体和七个回购。我将为你儿子提供链接这里有一个链接,指向从实体到控制器的所有类:是的,这个答案很有魅力,但如果你有很多孩子或父母或其他“重”(RAM使用方面)的话,它会有缓慢的一面关系。有没有一种方法可以在不加载洞实体的情况下归档完全相同的结果?我认为有一种方法,你必须多读一些关于它的内容,因为我不确定我是否可以解释它。因为这是一种多对多关系,你可以使用EmbeddedId
而不是通常的ID生成,这样可以节省你的时间r childName和parent。这可能会解决您的问题,并且在保存之前不必加载子项。好的。@3asyPe答案对于您发布的原始问题是正确的,除了childRpo.save(newChild)如果您有cascade on parent,则不需要使用
。现在您的功能没有问题。您在此处的评论是一个单独的问题,因此可能会提出一个单独的问题。或者,检查如何将您的父实体加载为代理,如果您当前的问题是PerformanceEyes,则直接使用代理保存子实体。这个答案很有魅力,但我如果你有很多孩子,那就慢了
| Parent | | parent_child_mapping | | Child |
| id | name | | child_id | parent_id | | id | name |
| 1 | pa1 | | 1 | 1 | | 1 | child1 |
| 2 | pa2 | | 2 | 1 | | 2 | child2 |
| 3 | 2 | | 3 | child1 |
| Parent | | parent_child_mapping | | Child |
| id | name | | child_id | parent_id | | id | name |
| 1 | pa1 | | 1 | 1 | | 1 | child1 |
| 2 | pa2 | | 2 | 1 | | 2 | child2 |
| 1 | 2 |
Book -- oneToMany --> Page -- oneToMany --> Version -- ManyToOne --> Author
Book -- oneToMany --> Locations
..
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto= update
Parent p = parentRepo.findByName(pName).get();
Child newChild;
Optional<Child> result = childRpo.findByName(cName);
if(result != null) {
newChild = result.get();
}
else {
newChild = new Child(cName);
}
p.getChilds.add(newChild);
newChild.getParents().add(p);
parentRepo.save(p);