序列号的 JPA 映射错误

标签 jpa eclipselink java-ee-6

我一直在构建应用程序的一部分来保存用户的仪表板对象,而 JPA 已经困扰了我很长时间。

我有一个抽象的 Widget 类,随着更多仪表板对象的开发,所有仪表板对象都将扩展该类。它们包含在通过 JPA 保存的 WidgetList 类中。对我来说,代码看起来不错,但我仍然是 Java EE 6 和 JPA 的新手。当我尝试部署时,出现以下错误:

    Exception [EclipseLink-41] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: A non-read-only mapping must be defined for the sequence number field.
Descriptor: RelationalDescriptor(ui.dashboard.widgetlist.WidgetList --> [DatabaseTable(WIDGETLIST)])
Runtime Exceptions: 
---------------------------------------------------------
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:478)
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:406)
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.postConnectDatasource(DatabaseSessionImpl.java:671)
        at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:620)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:228)
        at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:369)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:151)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:207)
        at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:202)
        at com.sun.enterprise.container.common.impl.EntityManagerWrapper._getDelegate(EntityManagerWrapper.java:197)
        at com.sun.enterprise.container.common.impl.EntityManagerWrapper.createNamedQuery(EntityManagerWrapper.java:554)
        at ca.comdev.cdip.mis.enterpriseportal.workflow.task.reminder.ReminderJpaDao.readAll(ReminderJpaDao.java:71)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1056)
        at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1128)
        at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5292)
        at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:615)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:797)
        at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:567)
        at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:57)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:858)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:797)
        at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:567)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:157)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:139)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:858)
        at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:797)
        at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:367)
        at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5264)
        at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5252)
        at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:190)
        at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:84)
        at $Proxy188.readAll(Unknown Source)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304)
        at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
        at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
        at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298)
        at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:127)
        at org.jboss.weld.util.CleanableMethodHandler.invoke(CleanableMethodHandler.java:43)
        at workflow.task.reminder.ReminderDao_$$_javassist_79.readAll(ReminderDao_$$_javassist_79.java)
        at workflow.task.reminder.ReminderSchedulerImpl.retrieveAllReminders(ReminderSchedulerImpl.java:117)
        at workflow.task.reminder.ReminderSchedulerImpl.initialize(ReminderSchedulerImpl.java:92)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.sun.ejb.containers.interceptors.BeanCallbackInterceptor.intercept(InterceptorManager.java:1006)
        at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:61)
        at com.sun.ejb.containers.interceptors.CallbackInvocationContext.proceed(CallbackInvocationContext.java:109)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCallback(SystemInterceptorProxy.java:133)
        at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.init(SystemInterceptorProxy.java:115)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.sun.ejb.containers.interceptors.CallbackInterceptor.intercept(InterceptorManager.java:961)
        at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:61)
        at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:390)
        at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:373)
        at com.sun.ejb.containers.AbstractSingletonContainer.createSingletonEJB(AbstractSingletonContainer.java:521)
        at com.sun.ejb.containers.AbstractSingletonContainer.access$100(AbstractSingletonContainer.java:74)
        at com.sun.ejb.containers.AbstractSingletonContainer$SingletonContextFactory.create(AbstractSingletonContainer.java:696)
        at com.sun.ejb.containers.AbstractSingletonContainer.instantiateSingletonInstance(AbstractSingletonContainer.java:444)
        at org.glassfish.ejb.startup.SingletonLifeCycleManager.initializeSingleton(SingletonLifeCycleManager.java:213)
        at org.glassfish.ejb.startup.SingletonLifeCycleManager.initializeSingleton(SingletonLifeCycleManager.java:174)
        at org.glassfish.ejb.startup.SingletonLifeCycleManager.doStartup(SingletonLifeCycleManager.java:152)
        at org.glassfish.ejb.startup.EjbApplication.start(EjbApplication.java:150)
        at org.glassfish.internal.data.EngineRef.start(EngineRef.java:126)
        at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:241)
        at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:236)
        at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:339)
        at com.sun.enterprise.v3.server.ApplicationLoaderService.processApplication(ApplicationLoaderService.java:362)
        at com.sun.enterprise.v3.server.ApplicationLoaderService.postConstruct(ApplicationLoaderService.java:185)
        at com.sun.hk2.component.AbstractWombImpl.inject(AbstractWombImpl.java:174)
        at com.sun.hk2.component.ConstructorWomb$1.run(ConstructorWomb.java:87)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.sun.hk2.component.ConstructorWomb.initialize(ConstructorWomb.java:84)
        at com.sun.hk2.component.AbstractWombImpl.get(AbstractWombImpl.java:77)
        at com.sun.hk2.component.SingletonInhabitant.get(SingletonInhabitant.java:58)
        at com.sun.hk2.component.LazyInhabitant.get(LazyInhabitant.java:107)
        at com.sun.hk2.component.AbstractInhabitantImpl.get(AbstractInhabitantImpl.java:60)
        at com.sun.enterprise.v3.server.AppServerStartup.run(AppServerStartup.java:236)
        at com.sun.enterprise.v3.server.AppServerStartup.start(AppServerStartup.java:128)
        at com.sun.enterprise.module.bootstrap.Main.launch(Main.java:457)
        at com.sun.enterprise.module.bootstrap.Main.launch(Main.java:401)
        at org.jvnet.hk2.osgiadapter.HK2Main.start(HK2Main.java:125)
        at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:640)
        at org.apache.felix.framework.Felix.activateBundle(Felix.java:1700)
        at org.apache.felix.framework.Felix.startBundle(Felix.java:1622)
        at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:915)
        at org.jvnet.hk2.osgimain.Main.start(Main.java:140)
        at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:640)
        at org.apache.felix.framework.Felix.activateBundle(Felix.java:1700)
        at org.apache.felix.framework.Felix.startBundle(Felix.java:1622)
        at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1077)
        at org.apache.felix.framework.StartLevelImpl.run(StartLevelImpl.java:264)
        at java.lang.Thread.run(Thread.java:619)

我的 WidgetList 代码在这里:

package ui.dashboard.widgetlist;

import principals.Principal;
import ui.dashboard.widgets.Widget;
import java.io.Serializable;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MapsId;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

/**
 * The storage class for the Widgets that a user has saved to their
 * profile.
 * @author mtatham
 */
@Entity
@Table(name="WIDGETLIST")
@NamedQueries({
    @NamedQuery(name="widgetlist.byOwner",query="select w from WidgetList w where w.owner = :owner")
})
public class WidgetList implements Serializable {

    /**
     * The system generated ID
     */

    @Id
    @GeneratedValue
    @Column(name="WIDGETLIST_ID", nullable = false, insertable=true,updatable=true )
    private Integer id;

    /**
     * The user principal used for the lookup on the database
     */
    @OneToOne @MapsId
    private Principal owner;

    /**
     * The Set of Widgets associated with the owner.
     */
    @OneToMany(mappedBy="currentWidgetList", cascade=CascadeType.ALL, orphanRemoval=true,fetch=FetchType.LAZY)
    private Set<Widget> widgetList = new LinkedHashSet<Widget>();

    public Integer getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Principal getOwner() {
        return owner;
    }

    public void setOwner(Principal owner) {
        this.owner = owner;
    }

    public Set<Widget> getWidgetList() {
        return this.widgetList;
     }

    public void setWidgetList(Set<Widget> widgetList) {
        this.widgetList = widgetList;
    }

    /**
     * Adds a new Widget to the Set.  If the set already contains the
     * unique Widget being added, the method will end gracefully.
     * @param widget
     */
    public void addWidget(Widget widget) {
        if(this.widgetList.contains(widget)){
            return;
        }else {
            widget.setCurrentWidgetList(this);
            this.widgetList.add(widget);
        }
    }

    @Override
    public String toString() {
        if(getOwner()!=null){
            return getId() + " - " + getOwner().getName();
        } else{
            return getId().toString();
        }
    }



    public boolean equals(WidgetList wl) {
        return true;
    }

并且,为了完整起见,WidgetList 存储的抽象 Widget 类:

import ui.dashboard.widgetlist.WidgetList;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 * This is the class used as the template for all of the customized widgets
 * that will be included on the Enterprise Portal dashboard.  This abstract
 * class will contain the generic information required for the user's
 * customized dashboard.
 *
 * Any new widgets for the dashboard must extend this class and add their
 * custom data elements.
 * @author mtatham
 */
@Entity
@Table(name = "WIDGETS")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "TYPE")
public abstract class Widget implements Serializable{

    /**
     * The ID of the Widget.  Generated programmatically.
     */
    @Id
    @GeneratedValue
    @Column(name="WIDGET_ID")
    private int id;
    /**
     * The id name used on the JSF page to identify the object
     */
    @Column(name = "IDNAME")
    private String idName;

    /**
     * The WidgetList this Widget is currently assigned to. 
     */
    @ManyToOne(optional=false)
    @JoinColumn(name = "CURRENT_WIDGETLIST_ID", nullable=false)
    private WidgetList currentWidgetList;
    /**
     * Header name that is visible on the widget menu
     */
    @Column(name = "HEADER")
    private String headerName;
    /**
     * JSF property that determines if a user can hide the widget.  This will
     * be defaulted to 'true'.  The only other value acceptable is 'false'.
     *
     * This is a String element even though there are only boolean values
     * due to the data being used in the xhtml pages.
     */
    @Column(name = "TOGGLEABLE")
    private String toggleable = "true";
    /**
     * JSF property that determines if a user can close a widget to remove it
     * from the dashboard.  This will be defaulted to 'true'.  The only other
     * value acceptable is 'false'.
     *
     * This is a String element even though there are only boolean values
     * due to the data being used in the xhtml pages.
     */
    @Column(name = "CLOSABLE")
    private String closable = "true";
    /**
     * This is an override to change the CSS style on the widget.
     */
    @Column(name = "STYLE")
    private String style;
    /**
     * Determines what part of the widget can be grabbed with the cursor to
     * move it around.  The default will be the header of the widget.
     */
    @Column(name = "HANDLE")
    private String handle = ".ui-panel-titlebar";
    /**
     * Determines the transparency of the widget while it is being dragged.
     * This is a decimal number between 0 and 1.  The default will be 1.
     */
    @Column(name = "OPACITY")
    private String opacity = "1";

    /**
     * This is the form object that the widget will be loaded into.  This will
     * be defaulted to widgetTemplate.xhtml.  It can be overwritten in the
     * extended classes.
     */
    @Column(name="FORM")
    private String xhtmlForm = "";

    public WidgetList getCurrentWidgetList() {
        return currentWidgetList;
    }

    public void setCurrentWidgetList(WidgetList widgetList) {
        this.currentWidgetList = widgetList;
    }

    public String getClosable() {
        return closable;
    }

    public String getHandle() {
        return handle;
    }

    public String getHeaderName() {
        return headerName;
    }

    public int getId() {
        return id;
    }

    public String getIdName() {
        return idName;
    }

    public String getOpacity() {
        return opacity;
    }

    public String getStyle() {
        return style;
    }

    public String getToggleable() {
        return toggleable;
    }

    public String getXhtmlForm() {
        return xhtmlForm;
    }

    public void setClosable(String closable) {
        this.closable = closable;
    }

    public void setHandle(String handle) {
        this.handle = handle;
    }

    public void setHeaderName(String headerName) {
        this.headerName = headerName;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setIdName(String idName) {
        this.idName = idName;
    }

    public void setOpacity(String opacity) {
        this.opacity = opacity;
    }

    public void setStyle(String style) {
        this.style = style;
    }

    public void setToggleable(String toggleable) {
        this.toggleable = toggleable;
    }

    public void setXhtmlForm(String xhtmlForm) {
        this.xhtmlForm = xhtmlForm;
    }

}

这是用 Java EE 6 编写的,使用 JPA,使用 MySQL 数据库部署到 Glassfish 3.0.1 服务器。我使用 NetBeans 6.9.1 作为开发环境,机器上安装了 jdk 1.6.0_20。我们使用此版本是因为我们与仍在维护的旧软件存在依赖关系。

我对这个问题的理解是,WidgetList 类上的 @Id 注释字段“id”被标识为只读。我尝试通过使用 @Column 注释手动强制将其识别为非只读字段,但无济于事。

我一直在 Oracle 论坛、stackoverflow 以及 google 可以带我去的任何地方寻找,但我完全没有找到解决方案。我对EclipseLink wiki page寄予厚望,但事实证明它也失败了。实际的错误描述没有告诉我任何信息。

如果有人有任何想法,我们将不胜感激。

谢谢, 马特·塔瑟姆

最佳答案

我不完全理解为什么会发生这个特定的错误,但似乎我错误地使用了 @MapsId 注释。从我找到的文档中,注释应该用于链接到另一个类中的 @EmbeddedId 主键。我用它来映射到属于我的类的 id,JPA 将隐式执行此操作,而无需告知。

删除 @MapsId 标记解决了该问题,并允许 JPA 毫无问题地创建我的数据库表。

关于序列号的 JPA 映射错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5330307/

相关文章:

java - Hibernate @ManyToMany 类注释配置

java - 使用 MOXy 使用默认的 minOccurs 生成模式

java - 使用 JBoss 7.1.1.Final AS 进行 XML Doctype 验证

java - 如何从 JAX-WS Web 服务中的编程授权检查返回正确的 HTTP 状态代码?

Eclipse m2e 上的 Maven Jboss 原型(prototype)目录

java - JPA:回滚后刷新分离的实体并重新附加它

hibernate - java.lang.ClassCastException : org. springframework.orm.hibernate5.SessionHolder 无法转换为 org.springframework.orm.jpa.EntityManagerHolder

hibernate - JPA 创建 @ManyToMany 表名不是由 'type_type' 而是由 'type_varname'

java - 创建jpa后自动填充表格

java - @Id 不创建主键