Spring存储库问题
我似乎对JPA存储库应该如何工作感到困惑。 在坚果壳里Spring存储库问题,spring,jpa,spring-data,Spring,Jpa,Spring Data,我似乎对JPA存储库应该如何工作感到困惑。 在坚果壳里 @Entity public class User extends AbstractEntity { protected final static String FK_NAME = "USER_ID"; @Column(nullable = false) private String firstName; @OneToMany(cascade = ALL, fetch = FetchType.LAZY,
@Entity
public class User extends AbstractEntity {
protected final static String FK_NAME = "USER_ID";
@Column(nullable = false)
private String firstName;
@OneToMany(cascade = ALL, fetch = FetchType.LAZY, orphanRemoval = true)
@JoinColumn(name = "userId")
private List<Detail> details = new ArrayList<Detail>();
}
@Entity
public class Detail extends AbstractEntity {
Long userId;
String hello;
}
@Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findByFirstName(@Param("firstName") String firstName);
}
下面是调试会话的屏幕截图,其中应用程序刚刚启动,get request to home()方法创建新用户、新详细信息,并向用户添加详细信息。
下面的示例-保存用户时,详细信息实体将更新
现在在下一个请求中,找到了老用户John,并添加了一个新的详细信息实例。
旧用户已保存,但新创建的详细信息不会在外部更新。
<> P>为什么这只是第一次工作?
非常简单,第一次你在Hibernate会话之外保存了一个新的实体,第二次,你得到的用户对象是一个分离的对象,默认情况下Hibernate不会认为在这种情况下被改变了。p> *解决方案* 将此逻辑移动到另一个服务类,该服务类用@transactional注释 或 用事务性注释控制器 或
用户类上的Override equals和hashCode方法也可能有帮助基本上,有太多的失败发生,所以我建议您后退一步。如果你想找到解决这个问题的方法,继续阅读;) 第一部分与Jaiwo99的答案相关: 正如我在intellij的gradle视图中看到的,您正在使用Spring Boot。因此,有必要将@EnableTransactionManagement放在配置类的顶部。否则,@Transacion注释将不起任何作用 第二部分是JPA/Hibernate模型映射。网上有这么多不好的练习,难怪大多数初学者在开始时都有困难 正确的版本可能看起来像(未测试)
@实体
公共类用户扩展抽象实体{
@列(nullable=false)
私有字符串名;
@OneToMany(cascade=ALL,fetch=FetchType.LAZY,orphanRemoving=true,mappedBy=“user”)
私有列表详细信息=新建ArrayList();
公共无效添加详细信息(详细信息){
详细信息。添加(详细信息);
detail.setUser(用户);
}
}
@实体
公共类细节扩展了抽象实体{
@许多酮
私人用户;
私人字符串你好;
公共void setUser(用户){
this.user=用户;
}
}
有关创建模型映射的一些一般建议:
- 尽可能避免双向映射
- 级联是在服务级别而不是在模型级别做出的决策,可能存在巨大的缺点。所以对于初学者来说,要避免它李>
- 我不知道为什么人们喜欢将JoinColumn、JoinTable和任何连接注释放在字段的顶部。这样做的唯一原因是当你有一个遗留数据库(我的意见)。如果您不喜欢jpa提供商创建的名称,请提供不同的命名策略
- 我将为用户类提供一个自定义名称,因为在某些数据库中这是一个保留字
userId
字段,因为此列由OneToMany关联处理。@JBNizet我在问-为什么在创建新用户时,向User.details添加一个新的详细信息,然后保存新创建的用户-详细信息会用一个ID更新,但当我从数据库中获取创建的用户时,创建新的详细信息,并将该详细信息添加到用户,然后再次保存用户-user.Detail列表中的详细信息实例会更新,但传递给用户的实例不会更新。为什么它只在第一次工作。您是否提交了事务并查看了详细信息是否用ID保存在数据库中?我使用的是内存中的hsqldb。至少当我通过存储库获取它们时,它们就在那里了。您的JPA实现确实如此。如果它没有运行它,那是因为它不正确,所以请修复它。你只需要学习你正在使用的工具。它们不会按照您认为应该的方式工作。我尝试过使用javax.transaction.Transactional或org.springframework.transaction.annotation.Transactional进行注释,但仍然得到相同的结果。。。其实很奇怪,谢谢。还有一件事-假设详细信息
实体没有对用户
实体的反向引用。单向映射示例[此处]()连接列创建了一个附加列,这样当您有电话时,您仍然可以查询员工。如果使用spring数据“@Query”,我会怎么做?因为我已经尝试了EverythSign,但是失败了,因为@EntityI上没有物理属性。我会从用户中删除对细节的引用。在这种情况下,您也可以避免n+1选择问题。除此之外,还可以使用类似以下内容的查询“从用户u中选择u,其中:u.details的详细成员”。问题解决后,请将消息标记为正确。
@RestController
public class Home {
@Autowired
UserRepository userRepository;
@Autowired
DetailsRepository loanRepository;
@RequestMapping(value = "")
public HttpEntity home() {
User user = userRepository.findByFirstName("John");
if (user == null) {
user = new User();
user.setFirstName("John");
}
Detail detail = new Detail();
detail.setHello("Hello Msh");
user.getDetails().add(detail);
userRepository.save(user);
return new ResponseEntity("hi", HttpStatus.OK);
}
}
@Entity
public class User extends AbstractEntity {
@Column(nullable = false)
private String firstName;
@OneToMany(cascade = ALL, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy="user")
private List<Detail> details = new ArrayList<Detail>();
public void addDetail(Detail detail) {
details.add(detail);
detail.setUser(user);
}
}
@Entity
public class Detail extends AbstractEntity {
@ManyToOne
private User user;
private String hello;
public void setUser(User user){
this.user = user;
}
}