2013-05-07 3 views
1

Я пишу простое приложение с использованием Spring и JPA. У меня есть 2 объекта: Пользователь и Роль, с отношением N..1.JPA: исключение, получающее объект, который ссылается на другой

Всякий раз, когда я пытаюсь получить любое из этих сущностей из базы данных, я получаю исключение (это показано ниже). Указанное исключение возникает, когда один объект пытается получить другой объект через свой внешний ключ.

Например, когда я запрашиваю роль, все ее атрибуты получены правильно, за исключением 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 из объекта Role. Если я пытаюсь получить роль она работает просто отлично, но если я пытаюсь найти пользователя, я получаю следующее исключение:



    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

Прежде всего, вы не укажете свой макет таблицы, что дает ответ на ваш вопрос в игре угадывания.

Для начала я бы не использовал @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; 

Если идентификатор в основном имя пользователя, это плохая идея. Если пользователь хочет изменить свое имя пользователя, может возникнуть сложная ситуация. Кроме того, ссылки на внешние ключи для таблицы 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 не требуется, так как столбец ID в roles использует имя по умолчанию:

@ManyToOne(optional = false, fetch = FetchType.EAGER) 
@JoinColumn(name = "rol") 
private Role 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 позволяют вам для указания фактических имен столбцов. Они не относятся к именам полей в ваших классах.
Смежные вопросы