【问题标题】:JPA: exception obtaining an entity that references anotherJPA:获取引用另一个实体的异常
【发布时间】:2013-05-01 23:53:09
【问题描述】:

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

每当我尝试从数据库中获取任何此类实体时,都会出现异常(如下所示)。当一个实体试图通过其外键获取另一个实体时,将引发所述异常。

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

无论我使用哪种方法询问实体(.find(pk)、.createNamedQuery()、.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)
        ...

我试图从角色实体中删除 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)
        ...

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

【问题讨论】:

    标签: java spring exception jpa


    【解决方案1】:

    首先,您没有指明您的桌子布局,这使得回答您的问题成为一种猜谜游戏。

    首先,我会避免在User 的 ID 列上使用 @Basic@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 属性允许您指定实际的列名。它们不引用您的类中的字段名称。

    【讨论】:

      猜你喜欢
      • 2011-07-16
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多