我正在使用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)
...
我不知道如何解决这个问题。我花了很多时间。帮助将不胜感激:))
答案 0 :(得分:0)
首先,你没有表明你的桌面布局,这使得回答你的问题成为猜谜游戏。
首先,我会避免在@Basic
的ID列上使用User
。 @Size
没问题,但您可能也希望在JPA中与之匹配。请参阅下文(nullable=false
和unique=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
等)中,name
和referencedColumnName
属性允许您指定实际的列名称。它们不会引用您班级中的字段名称。