JPA:获取引用另一个实体的实例的异常

时间:2013-05-07 21:40:29

标签: java spring exception jpa

我正在使用Spring和JPA编写一个简单的应用程序。我有2个实体:用户和角色,关系为N..1。

每当我尝试从数据库中获取任何这些实体时,我都会得到一个异常(如下所示)。当一个实体试图通过其外键获取另一个实体时,抛出所述异常。

例如,当我要求一个角色时,除了userCollection(分配给该角色的用户组)之外,其所有属性都是正确获取的。

无论我使用哪种方法询问实体(.find(pk),. createZamedQuery(),. createQuery(),...),都会抛出异常。

以下是代码。我已经跳过了不相关的部分:

用户实体:



    @Entity
    @Table(name = "users")
    public class User implements Serializable {

        private static final long serialVersionUID = 1L;

        @Id
        @Basic(optional = false)
        @Size(min = 1, max = 50)
        private String id;

        @JoinColumn(name = "rol", referencedColumnName = "id")
        @ManyToOne(optional = false, fetch = FetchType.EAGER)
        private Role rol;

        ...

角色实体:



    @Entity
    @Table(name = "roles")
    public class Role implements Serializable {
        private static final long serialVersionUID = 1L;

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;

        @NotNull
        @Size(min = 1, max = 50)
        private String name;

        @OneToMany(cascade = CascadeType.ALL, mappedBy = "rol", fetch = FetchType.LAZY)
        private Collection userCollection;

        ...

尝试获取角色时抛出的异常:


    Exception [EclipseLink-6094] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.QueryException
    Exception Description: The parameter name [id] in the query's selection criteria does not match any parameter name defined in the query.
    Query: ReadAllQuery(name="userCollection" referenceClass=User sql="SELECT ID, EMAIL, NAME, rol FROM users WHERE (rol = ?)")
        at org.eclipse.persistence.exceptions.QueryException.parameterNameMismatch(QueryException.java:1031)
        at org.eclipse.persistence.internal.expressions.ParameterExpression.getValue(ParameterExpression.java:246)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseCall.translate(DatabaseCall.java:918)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:204)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:191)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelectCall(DatasourceCallQueryMechanism.java:262)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectAllRows(DatasourceCallQueryMechanism.java:618)
        at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRowsFromTable(ExpressionQueryMechanism.java:2537)
        at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2496)
        at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:455)
        at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:997)
        at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:675)
        at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:958)
        at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:432)
        ...

我尝试从Role实体中删除userCollection。如果我尝试获得一个角色它可以正常工作,但如果我试图找到一个用户,我会得到以下异常:



    org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Transaction marked for rollback.
        at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1014)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
        ...

我不知道如何解决这个问题。我花了很多时间。帮助将不胜感激:))

1 个答案:

答案 0 :(得分:0)

首先,你没有表明你的桌面布局,这使得回答你的问题成为猜谜游戏。

首先,我会避免在@Basic的ID列上使用User@Size没问题,但您可能也希望在JPA中与之匹配。请参阅下文(nullable=falseunique=true属性在@Id注释中是多余的:

@Id
@Column(length=50, nullable=false, unique=true)
@Size(min = 1, max = 50)
private String id;

如果ID基本上是用户名,这是一个坏主意。如果用户想要更改其用户名,事情就会变得棘手。另外,对users表的外键引用需要50个字节而不是4个(它比这复杂一点,但你明白了)。我会添加常规Integer ID和单独的userName字段。用户永远不需要查看ID。

应该对Role.name进行类似的处理:

@Column(length=50, nullable=false, unique=true)
@Size(min = 1, max = 50)
private String name;

其次,看起来用户只能拥有一个角色?真的吗?无论如何,如果是这种情况,则不需要referencedColumnName属性,因为roles中的ID列使用默认名称:

@ManyToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "rol")
private Role rol;

将外键列命名为“rol”而不是“role_id”不是一个好主意。我会使用默认值(只需删除@JoinColumn内容)。

如果您打算让用户拥有多个角色,则需要一个联接表(如果您想使用默认值,则可以省略@JoinTable内容):

@ManyToMany
@JoinTable(
    name = "user_roles",
    joinColumns = { @JoinColumn(name = "user_id") },
    inverseJoinColumns = { @JoinColumn(name = "role_id") }
)
private List<Role> roles;

第三,很难看到在Role中拥有用户列表的有用性。我会完全删除它。而是使用user.getRoles.contains(SomeRole)之类的内容来查看用户是否具有某个角色。

最后,看看你的代码,我应该清楚一些事情:

  • 在“列”注释(@Column@JoinColumn等)中,namereferencedColumnName属性允许您指定实际的列名称。它们不会引用您班级中的字段名称。