Playframework:JPA EntityManager 合并函数失败 - 不使用主题成员变量值
Playframework: JPA EntityManager merge function fails - does not use subjects member variable values
在我描述问题之前,让我解释一下,我正在使用 Playframework 2.4.4,Hibernate 5.0.5 并使用纯 JPA 方法,即我无法访问 Hibernate 'saveOrUpdate' 方法,但必须使用 merge 或 persist。此外,根据 playframework 的最新建议(当不使用 ebean 时),我的模型 class 不会扩展 play.db.ebean.Model class。
问题:
我对 EntityManager.merge 的调用失败并出现异常 "NULL not allowed for column",尽管主题实例中的关联成员变量确实已填充!
详情:
- class;三个字段,其中两个组成复合主键。
- 有一个 class 的新实例,通过绑定 Play 表单填充。我检查了实例的内容,确实包含故障列的值。
- table 为空。
- 虽然填入了值,但是SQL指令并没有到达,因为涉及到主键,当然会出现异常
[错误] - org.hibernate.engine.jdbc.spi.SqlExceptionHelper - 列 "IDTYPECODE" 不允许为 NULL; SQL 声明:
问题:
然而,我的对象已经完全填满了。那为什么会这样呢?根据我所阅读的所有内容,在这种情况下,合并功能应该成功插入一个新的非冲突条目!我做错了什么?
Persist 将在这种情况下工作,但事实上,在我的特定情况下,我无法知道这个对象是否存在于数据库中。
我想避免查找以检查是否存在!以我的理解,应该是可以的!
更多详情:
这里是class定义
@Entity
public class IdType implements Serializable
{
/**
* User specified Unique identifier.
* Both idTypeCode and idCategory are together
* a compound key, so as to ensure that the
* combination of the both can not occur more
* than once in the table.
*/
@Id
public String idTypeCode;
@Id
public IdCategory idCategory;
public String idTypeName;
}
我的控制器很简单;
@Transactional
public Result updateIds()
{
IdType idType = Form.form(IdType.class).bindFromRequest().get();
System.out.println("idTypeCode is: "+idType.idTypeCode);
EntityManager em = entityManager();
em.merge(idType);
return redirect(routes.Application.index());
}
尝试以这种方式保存此对象的控制台输出如下:
idTypeCode is: national_number
[error] - org.hibernate.engine.jdbc.spi.SqlExceptionHelper - NULL not allowed for column "IDTYPECODE"; SQL statement:
insert into IdType (idTypeName, idTypeCode, idCategory) values (?, ?, ?) [23502-187]
[error] - play.core.server.netty.PlayDefaultUpstreamHandler - Cannot invoke the action
javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:86) ~[hibernate-entitymanager-5.0.5.Final.jar:5.0.5.Final]
at play.db.jpa.DefaultJPAApi.withTransaction(DefaultJPAApi.java:142) ~[play-java-jpa_2.11-2.4.4.jar:2.4.4]
at play.db.jpa.JPA.withTransaction(JPA.java:159) ~[play-java-jpa_2.11-2.4.4.jar:2.4.4]
at play.db.jpa.TransactionalAction.call(TransactionalAction.java:16) ~[play-java-jpa_2.11-2.4.4.jar:2.4.4]
at play.core.j.JavaAction$$anonfun.apply(JavaAction.scala:94) ~[play_2.11-2.4.4.jar:2.4.4]
如您所见,假设对象不存在,在这种情况下 SQL 语句 运行 正是我所希望的:
insert into IdType (idTypeName, idTypeCode, idCategory) values (?, ?, ?) [23502-187]
然而,出于某种原因,即使我知道我的对象中有 'idTypeName' 的值,它告诉我:
[error] - org.hibernate.engine.jdbc.spi.SqlExceptionHelper - NULL not allowed for column "IDTYPECODE"; SQL statement:
那么,为什么它忽略了我明显填充的值?
我在别处读到合并应该有效;即,如果对象存在于数据库中,它将执行更新,如果不存在,则执行插入。
这种奇怪的行为是 Playframework 改变 JPA 库的正常行为的结果吗(在这种情况下我使用的是 Hibernate)。
有什么想法吗?
更新!!!!!
好的,终于有时间亲自深入研究一下了。
看来这跟玩没什么关系。
我刚才使用直接 JPA/Hibernate 控制台应用程序测试了相同的场景。我遇到了同样的问题。
一旦我有一个复合键(就像我在给定的示例中所做的那样),就会出现问题。
只要我删除其中一列作为键,合并就会起作用。
现在我正在研究为什么会这样,以及如何避免这个问题(同时仍然拥有我需要的模型)。
我会在获得更多信息后立即更新此问题。
好的。所以我终于解决了。
好像我在错误地构建我的 JPA compound/composite 主键。
我想我可以简单地单独用 Id 注释指定我的组合键。像这样:
@Entity
public class IdType implements Serializable
{
/**
* User specified Unique identifier.
* Both idTypeCode and idCategory are together
* a compound key, so as to ensure that the
* combination of the both can not occur more
* than once in the table.
*/
@Id
public String idTypeCode;
@Id
public IdCategory idCategory;
public String idTypeName;
}
但我错了。
我需要使用单独的 IdClass。否则,我会收到如前所述的神秘错误消息。
现在我的 class(es) 看起来像这样:
@Entity @IdClass(IdTypeCompoundId.class)
public class IdType implements Serializable
{
/**
* User specified Unique identifier.
* Both idTypeCode and idCategory are together
* a compound key, so as to ensure that the
* combination of the both can not occur more
* than once in the table.
*/
@Id
public String idTypeCode;
@Id
public IdCategory idCategory;
public String idTypeName;
}
public class IdTypeCompoundId implements Serializable
{
public String idTypeCode;
public IdCategory idCategory;
}
一切都很开心。合并没有问题。
即,第一次合并导致插入,具有相同详细信息的第二次合并(在我的例子中,例如,不同的 idTypeName)导致更新 table IdType 的现有行。
我不太明白为什么 JPA 需要使用单独的 'IdClass' 指定 table 来制作复合键。我原以为它通过两个(在我的例子中)用 id 注释的属性拥有它需要的所有信息。
但显然这还不够好。
总之,问题解决了。
我希望有一天这对某人有所帮助。
在我描述问题之前,让我解释一下,我正在使用 Playframework 2.4.4,Hibernate 5.0.5 并使用纯 JPA 方法,即我无法访问 Hibernate 'saveOrUpdate' 方法,但必须使用 merge 或 persist。此外,根据 playframework 的最新建议(当不使用 ebean 时),我的模型 class 不会扩展 play.db.ebean.Model class。
问题:
我对 EntityManager.merge 的调用失败并出现异常 "NULL not allowed for column",尽管主题实例中的关联成员变量确实已填充!
详情:
- class;三个字段,其中两个组成复合主键。
- 有一个 class 的新实例,通过绑定 Play 表单填充。我检查了实例的内容,确实包含故障列的值。
- table 为空。
- 虽然填入了值,但是SQL指令并没有到达,因为涉及到主键,当然会出现异常 [错误] - org.hibernate.engine.jdbc.spi.SqlExceptionHelper - 列 "IDTYPECODE" 不允许为 NULL; SQL 声明:
问题:
然而,我的对象已经完全填满了。那为什么会这样呢?根据我所阅读的所有内容,在这种情况下,合并功能应该成功插入一个新的非冲突条目!我做错了什么? Persist 将在这种情况下工作,但事实上,在我的特定情况下,我无法知道这个对象是否存在于数据库中。 我想避免查找以检查是否存在!以我的理解,应该是可以的!
更多详情:
这里是class定义
@Entity
public class IdType implements Serializable
{
/**
* User specified Unique identifier.
* Both idTypeCode and idCategory are together
* a compound key, so as to ensure that the
* combination of the both can not occur more
* than once in the table.
*/
@Id
public String idTypeCode;
@Id
public IdCategory idCategory;
public String idTypeName;
}
我的控制器很简单;
@Transactional
public Result updateIds()
{
IdType idType = Form.form(IdType.class).bindFromRequest().get();
System.out.println("idTypeCode is: "+idType.idTypeCode);
EntityManager em = entityManager();
em.merge(idType);
return redirect(routes.Application.index());
}
尝试以这种方式保存此对象的控制台输出如下:
idTypeCode is: national_number
[error] - org.hibernate.engine.jdbc.spi.SqlExceptionHelper - NULL not allowed for column "IDTYPECODE"; SQL statement:
insert into IdType (idTypeName, idTypeCode, idCategory) values (?, ?, ?) [23502-187]
[error] - play.core.server.netty.PlayDefaultUpstreamHandler - Cannot invoke the action
javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:86) ~[hibernate-entitymanager-5.0.5.Final.jar:5.0.5.Final]
at play.db.jpa.DefaultJPAApi.withTransaction(DefaultJPAApi.java:142) ~[play-java-jpa_2.11-2.4.4.jar:2.4.4]
at play.db.jpa.JPA.withTransaction(JPA.java:159) ~[play-java-jpa_2.11-2.4.4.jar:2.4.4]
at play.db.jpa.TransactionalAction.call(TransactionalAction.java:16) ~[play-java-jpa_2.11-2.4.4.jar:2.4.4]
at play.core.j.JavaAction$$anonfun.apply(JavaAction.scala:94) ~[play_2.11-2.4.4.jar:2.4.4]
如您所见,假设对象不存在,在这种情况下 SQL 语句 运行 正是我所希望的:
insert into IdType (idTypeName, idTypeCode, idCategory) values (?, ?, ?) [23502-187]
然而,出于某种原因,即使我知道我的对象中有 'idTypeName' 的值,它告诉我:
[error] - org.hibernate.engine.jdbc.spi.SqlExceptionHelper - NULL not allowed for column "IDTYPECODE"; SQL statement:
那么,为什么它忽略了我明显填充的值?
我在别处读到合并应该有效;即,如果对象存在于数据库中,它将执行更新,如果不存在,则执行插入。 这种奇怪的行为是 Playframework 改变 JPA 库的正常行为的结果吗(在这种情况下我使用的是 Hibernate)。
有什么想法吗?
更新!!!!!
好的,终于有时间亲自深入研究一下了。 看来这跟玩没什么关系。 我刚才使用直接 JPA/Hibernate 控制台应用程序测试了相同的场景。我遇到了同样的问题。 一旦我有一个复合键(就像我在给定的示例中所做的那样),就会出现问题。 只要我删除其中一列作为键,合并就会起作用。 现在我正在研究为什么会这样,以及如何避免这个问题(同时仍然拥有我需要的模型)。 我会在获得更多信息后立即更新此问题。
好的。所以我终于解决了。 好像我在错误地构建我的 JPA compound/composite 主键。
我想我可以简单地单独用 Id 注释指定我的组合键。像这样:
@Entity
public class IdType implements Serializable
{
/**
* User specified Unique identifier.
* Both idTypeCode and idCategory are together
* a compound key, so as to ensure that the
* combination of the both can not occur more
* than once in the table.
*/
@Id
public String idTypeCode;
@Id
public IdCategory idCategory;
public String idTypeName;
}
但我错了。 我需要使用单独的 IdClass。否则,我会收到如前所述的神秘错误消息。 现在我的 class(es) 看起来像这样:
@Entity @IdClass(IdTypeCompoundId.class)
public class IdType implements Serializable
{
/**
* User specified Unique identifier.
* Both idTypeCode and idCategory are together
* a compound key, so as to ensure that the
* combination of the both can not occur more
* than once in the table.
*/
@Id
public String idTypeCode;
@Id
public IdCategory idCategory;
public String idTypeName;
}
public class IdTypeCompoundId implements Serializable
{
public String idTypeCode;
public IdCategory idCategory;
}
一切都很开心。合并没有问题。 即,第一次合并导致插入,具有相同详细信息的第二次合并(在我的例子中,例如,不同的 idTypeName)导致更新 table IdType 的现有行。
我不太明白为什么 JPA 需要使用单独的 'IdClass' 指定 table 来制作复合键。我原以为它通过两个(在我的例子中)用 id 注释的属性拥有它需要的所有信息。 但显然这还不够好。
总之,问题解决了。 我希望有一天这对某人有所帮助。