如何使用Hibernate保存ManyToOne关系。

huangapple go评论80阅读模式
英文:

How to save a ManyToOne Relationship using hibernate

问题

我有以下 User 实体。

  1. @Id
  2. @GeneratedValue(strategy = GenerationType.IDENTITY)
  3. @Column(name="user_id")
  4. private int id;
  5. @Embedded
  6. private Person person;
  7. @Column(columnDefinition = "VARCHAR(255)")
  8. private String image;
  9. @ManyToOne(fetch = FetchType.LAZY)
  10. @JoinColumn(name="user_group_id")
  11. private UserGroup userGroup;
  12. // 省略部分 getter 和 setter 方法
  13. public int getId() {
  14. return id;
  15. }
  16. public void setId(int id) {
  17. this.id = id;
  18. }
  19. public UserGroup getUserGroup() {
  20. return userGroup;
  21. }
  22. public void setUserGroup(UserGroup userGroup) {
  23. this.userGroup = userGroup;
  24. }

以及以下可嵌入的 Person 实体。

  1. @NotNull
  2. @Column(name="firstname", nullable = false, columnDefinition = "VARCHAR(32)")
  3. private String firstName;
  4. @NotNull
  5. @Column(name="lastname", nullable = false, columnDefinition = "VARCHAR(32)")
  6. private String lastName;
  7. @NotNull
  8. @Column(nullable = false, columnDefinition = "VARCHAR(96)")
  9. private String email;
  10. @NotNull
  11. @Column(nullable = false, columnDefinition = "VARCHAR(24)")
  12. private String telephone;
  13. @NotNull
  14. @Column(nullable = false, columnDefinition = "VARCHAR(255)")
  15. private String password;
  16. @Column(nullable = false, columnDefinition = "TINYINT(1) DEFAULT 1")
  17. private boolean status;
  18. @Column(name = "date_added", nullable = false, updatable=false, columnDefinition = "DATETIME DEFAULT CURRENT_TIMESTAMP")
  19. @Temporal(value = TemporalType.TIMESTAMP)
  20. private Date dateAdded;

以及以下 UserGroup 实体。

  1. @Id
  2. @GeneratedValue(strategy = GenerationType.IDENTITY)
  3. @Column(name="user_group_id")
  4. private int id;
  5. @NotNull
  6. @Column(nullable = false, columnDefinition = "VARCHAR(20)")
  7. private String name;
  8. @NotNull
  9. @Column(nullable = false, columnDefinition = "TEXT")
  10. private String permission;
  11. @OneToMany(mappedBy="userGroup",
  12. cascade={CascadeType.PERSIST, CascadeType.MERGE},
  13. fetch = FetchType.LAZY)
  14. private List<User> users = new ArrayList<User>();
  15. // 省略部分 getter 和 setter 方法

我已经在数据库中设置了几个用户组。当添加新用户时,我检索特定组并想将其分配给新用户。我使用以下代码来实现。

  1. Session session = HibernateHelper.getSessionFactory().openSession();
  2. UserGroup userGroup = (UserGroup) session.createQuery("FROM UserGroup UG WHERE UG.id = :user_group_id")
  3. .setParameter("user_group_id",Integer.parseInt(group))
  4. .getSingleResult();
  5. Transaction tx = session.getTransaction();
  6. tx.begin();
  7. User user = new User();
  8. user.setPerson(new Person());
  9. user.getPerson().setFirstName(firstName);
  10. user.getPerson().setLastName(lastName);
  11. user.getPerson().setEmail(email);
  12. user.getPerson().setTelephone(telephone);
  13. user.getPerson().setPassword(hashedPassword);
  14. user.setUserGroup(userGroup); // 将新用户分配给该组
  15. session.save(user);
  16. tx.commit();
  17. session.close();

然而,我收到异常:org.hibernate.exception.ConstraintViolationException。正确的做法是什么?

我正在开发一个基于 Wildfly 服务器的 Servlets 运行的 Web 应用程序。

错误堆栈跟踪:

  1. org.hibernate.exception.ConstraintViolationException: could not execute statement
  2. at deployment.shopping_cart.war//org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
  3. ...
  4. Caused by: java.sql.SQLIntegrityConstraintViolationException: Column 'date_added' cannot be null
  5. at deployment.shopping_cart.war//com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
  6. ...
英文:

I have the following User entity.

  1. @Id
  2. @GeneratedValue(strategy = GenerationType.IDENTITY)
  3. @Column(name=&quot;user_id&quot;)
  4. private int id;
  5. @Embedded
  6. private Person person;
  7. @Column(columnDefinition = &quot;VARCHAR(255)&quot;)
  8. private String image;
  9. @ManyToOne(fetch = FetchType.LAZY)
  10. @JoinColumn(name=&quot;user_group_id&quot;)
  11. private UserGroup userGroup;
  12. // Some getters and setters ommitted
  13. public int getId() {
  14. return id;
  15. }
  16. public void setId(int id) {
  17. this.id = id;
  18. }
  19. public UserGroup getUserGroup() {
  20. return userGroup;
  21. }
  22. public void setUserGroup(UserGroup userGroup) {
  23. this.userGroup = userGroup;
  24. }

And the following embeddable Person entity.

  1. @NotNull
  2. @Column(name=&quot;firstname&quot;, nullable = false, columnDefinition = &quot;VARCHAR(32)&quot;)
  3. private String firstName;
  4. @NotNull
  5. @Column(name=&quot;lastname&quot;, nullable = false, columnDefinition = &quot;VARCHAR(32)&quot;)
  6. private String lastName;
  7. @NotNull
  8. @Column(nullable = false, columnDefinition = &quot;VARCHAR(96)&quot;)
  9. private String email;
  10. @NotNull
  11. @Column(nullable = false, columnDefinition = &quot;VARCHAR(24)&quot;)
  12. private String telephone;
  13. @NotNull
  14. @Column(nullable = false, columnDefinition = &quot;VARCHAR(255)&quot;)
  15. private String password;
  16. @Column(nullable = false, columnDefinition = &quot;TINYINT(1) DEFAULT 1&quot;)
  17. private boolean status;
  18. @Column(name = &quot;date_added&quot;, nullable = false, updatable=false, columnDefinition = &quot;DATETIME DEFAULT CURRENT_TIMESTAMP&quot;)
  19. @Temporal(value = TemporalType.TIMESTAMP)
  20. private Date dateAdded;

And the following UserGroup entity.

  1. @Id
  2. @GeneratedValue(strategy = GenerationType.IDENTITY)
  3. @Column(name=&quot;user_group_id&quot;)
  4. private int id;
  5. @NotNull
  6. @Column(nullable = false, columnDefinition = &quot;VARCHAR(20)&quot;)
  7. private String name;
  8. @NotNull
  9. @Column(nullable = false, columnDefinition = &quot;TEXT&quot;)
  10. private String permission;
  11. @OneToMany(mappedBy=&quot;userGroup&quot;,
  12. cascade={CascadeType.PERSIST, CascadeType.MERGE},
  13. fetch = FetchType.LAZY)
  14. private List&lt;User&gt; users = new ArrayList&lt;User&gt;();
  15. // Getters and Setters ommitted

I already have a couple of user groups set up in the db. When adding a new user, I retrieve a specific group and want to assign it to the new user. I use the following code to do so.

  1. Session session = HibernateHelper.getSessionFactory().openSession();
  2. UserGroup userGroup = (UserGroup) session.createQuery(&quot;FROM UserGroup UG WHERE UG.id = :user_group_id&quot;)
  3. .setParameter(&quot;user_group_id&quot;,Integer.parseInt(group))
  4. .getSingleResult();
  5. Transaction tx = session.getTransaction();
  6. tx.begin();
  7. User user = new User();
  8. user.setPerson(new Person());
  9. user.getPerson().setFirstName(firstName);
  10. user.getPerson().setLastName(lastName);
  11. user.getPerson().setEmail(email);
  12. user.getPerson().setTelephone(telephone);
  13. user.getPerson().setPassword(hashedPassword);
  14. user.setUserGroup(userGroup); // Assign the new user this group
  15. session.save(user);
  16. tx.commit();
  17. session.close();

However I get the exception: org.hibernate.exception.ConstraintViolationException
What is the correct way to do this?

I'm developing a web app using servlets running on a wildfly server.

The error stack trace:

  1. org.hibernate.exception.ConstraintViolationException: could not execute statement
  2. at deployment.shopping_cart.war//org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
  3. at deployment.shopping_cart.war//org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
  4. at deployment.shopping_cart.war//org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
  5. at deployment.shopping_cart.war//org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
  6. at deployment.shopping_cart.war//org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
  7. at deployment.shopping_cart.war//org.hibernate.dialect.identity.GetGeneratedKeysDelegate.executeAndExtract(GetGeneratedKeysDelegate.java:57)
  8. at deployment.shopping_cart.war//org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:43)
  9. at deployment.shopping_cart.war//org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3153)
  10. at deployment.shopping_cart.war//org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3759)
  11. at deployment.shopping_cart.war//org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:84)
  12. at deployment.shopping_cart.war//org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:645)
  13. at deployment.shopping_cart.war//org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:282)
  14. at deployment.shopping_cart.war//org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:263)
  15. at deployment.shopping_cart.war//org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317)
  16. at deployment.shopping_cart.war//org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:330)
  17. at deployment.shopping_cart.war//org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:287)
  18. at deployment.shopping_cart.war//org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
  19. at deployment.shopping_cart.war//org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:123)
  20. at deployment.shopping_cart.war//org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:194)
  21. at deployment.shopping_cart.war//org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
  22. at deployment.shopping_cart.war//org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:179)
  23. at deployment.shopping_cart.war//org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
  24. at deployment.shopping_cart.war//org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:75)
  25. at deployment.shopping_cart.war//org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
  26. at deployment.shopping_cart.war//org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:634)
  27. at deployment.shopping_cart.war//org.hibernate.internal.SessionImpl.save(SessionImpl.java:627)
  28. at deployment.shopping_cart.war//org.hibernate.internal.SessionImpl.save(SessionImpl.java:622)
  29. at deployment.shopping_cart.war//controllers.UserCreate.doPost(UserCreate.java:51)
  30. at javax.servlet.api@2.0.0.Final//javax.servlet.http.HttpServlet.service(HttpServlet.java:523)
  31. at javax.servlet.api@2.0.0.Final//javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
  32. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
  33. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
  34. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
  35. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
  36. at org.wildfly.extension.undertow@20.0.1.Final//org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
  37. at io.undertow.core@2.1.3.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
  38. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
  39. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
  40. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
  41. at io.undertow.core@2.1.3.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
  42. at io.undertow.core@2.1.3.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
  43. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
  44. at io.undertow.core@2.1.3.Final//io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
  45. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
  46. at io.undertow.core@2.1.3.Final//io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
  47. at io.undertow.core@2.1.3.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
  48. at io.undertow.core@2.1.3.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
  49. at org.wildfly.extension.undertow@20.0.1.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
  50. at io.undertow.core@2.1.3.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
  51. at org.wildfly.extension.undertow@20.0.1.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
  52. at io.undertow.core@2.1.3.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
  53. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
  54. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
  55. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
  56. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
  57. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
  58. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
  59. at org.wildfly.extension.undertow@20.0.1.Final//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
  60. at org.wildfly.extension.undertow@20.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
  61. at org.wildfly.extension.undertow@20.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
  62. at org.wildfly.extension.undertow@20.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
  63. at org.wildfly.extension.undertow@20.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
  64. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
  65. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
  66. at io.undertow.servlet@2.1.3.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
  67. at io.undertow.core@2.1.3.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:370)
  68. at io.undertow.core@2.1.3.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
  69. at org.jboss.threads@2.3.3.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
  70. at org.jboss.threads@2.3.3.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982)
  71. at org.jboss.threads@2.3.3.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
  72. at org.jboss.threads@2.3.3.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
  73. at java.base/java.lang.Thread.run(Thread.java:832)
  74. Caused by: java.sql.SQLIntegrityConstraintViolationException: Column &#39;date_added&#39; cannot be null
  75. at deployment.shopping_cart.war//com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
  76. at deployment.shopping_cart.war//com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
  77. at deployment.shopping_cart.war//com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
  78. at deployment.shopping_cart.war//com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
  79. at deployment.shopping_cart.war//com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
  80. at deployment.shopping_cart.war//com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
  81. at deployment.shopping_cart.war//com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)
  82. at deployment.shopping_cart.war//com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025)
  83. at deployment.shopping_cart.war//org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
  84. ... 67 more

答案1

得分: 3

当您拥有以下字段时:

  1. @Column(name = "date_added", nullable = false, updatable=false, columnDefinition = "DATETIME DEFAULT CURRENT_TIMESTAMP")
  2. @Temporal(value = TemporalType.TIMESTAMP)
  3. private Date dateAdded;

如果不将 dateAdded 设置为适当的值(因此将其保留为 null),会导致所述的 ConstraintViolationException。因此,在初始化用户时,您需要设置 dateAdded,通常我会在构造函数或通过JPA注释来执行,但您也可以手动执行:

  1. [...]
  2. user.getPerson().setDateAdded(new Date());
  3. user.setUserGroup(userGroup); // 为新用户分配该组
  4. [...]

编辑:

因为我懒惰并且想要自动化事务,我大多数情况下使用注释来自动更新日期。我特别不喜欢特定于供应商的解决方案,因此通常使用JPA:

  1. public class Person {
  2. // ...
  3. @PrePersist
  4. public void prePersist() {
  5. dateAdded = new Date();
  6. }
  7. }

虽然Hibernate或Spring中有更复杂的解决方案,但效果始终相同:使用基于注释的机制,您不再需要手动设置 dateAdded

英文:

When you are having the field

  1. @Column(name = &quot;date_added&quot;, nullable = false, updatable=false, columnDefinition = &quot;DATETIME DEFAULT CURRENT_TIMESTAMP&quot;)
  2. @Temporal(value = TemporalType.TIMESTAMP)
  3. private Date dateAdded;

not setting dateAdded to a proper value (and therefore leaving it null) causes said ConstraintViolationException. So, on initializing the user you need to set dateAdded which I usually do in a constructor or via JPA annotations but you can also do that manually:

  1. [...]
  2. user.getPerson().setDateAdded(new Date());
  3. user.setUserGroup(userGroup); // Assign the new user this group
  4. [...]

Edit:

Because I am lazy and I want to automate things I mostly use annotations for auto-updates of dates. I particular don't like vendor specific solutions so I use JPA normally:

  1. public class Person {
  2. // ...
  3. @PrePersist
  4. public void prePersist() {
  5. dateAdded = new Date();
  6. }
  7. }

although there are more sophisticated solutions for Hibernate or Spring out there, but the effect is always the same: Using the annotation based mechanism you don't need to set dateAdded manually anymore.

huangapple
  • 本文由 发表于 2020年9月1日 15:38:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/63683318.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定