2015-06-06 18 views
1

我有一个实体CashFlow其实体类CashFlowCategorycategory。后者具有由字段nameusername组成的组合键。在数据库中,这些字段被称为NAMEUSERNAME休眠:嵌入ID字段命名问题

该应用程序工作正常使用的EclipseLink但是当我试图切换到休眠我就遇到了这个例外:

org.hibernate.HibernateException: Missing column: category_NAME in .APP.CASHFLOW 

看起来像Hibernate(不同的EclipseLink)预计category_前缀之前NAME,即使我明确状态

@Column(name="NAME") 
private String name; 

我怎么能告诉Hibernate来寻找“NAME”,而不是“CATEGORY_NAME”:该列应无前缀命名的?


设置:

  • Glassfish的4.0
  • 德比10.9.1.0

数据库结构:

表现金流:

COLUMN_NAME   |TYPE_NAME|DEC&|NUM&|COLUM&|COLUMN_DEF|CHAR_OCTE&|IS_NULL& 
------------------------------------------------------------------------------ 
ID     |INTEGER |0 |10 |10 |NULL  |NULL  |NO 
AMOUNT    |DOUBLE |NULL|2 |52 |NULL  |NULL  |YES 
DATE    |DATE  |0 |10 |10 |NULL  |NULL  |YES 
DESCRIPTION   |VARCHAR |NULL|NULL|255 |NULL  |510  |YES 
USERNAME   |VARCHAR |NULL|NULL|255 |NULL  |510  |YES 
NAME    |VARCHAR |NULL|NULL|255 |NULL  |510  |YES 
IDNUMBER   |INTEGER |0 |10 |10 |NULL  |NULL  |YES 

表CASHFLOWCATEGORY

COLUMN_NAME   |TYPE_NAME|DEC&|NUM&|COLUM&|COLUMN_DEF|CHAR_OCTE&|IS_NULL& 
------------------------------------------------------------------------------ 
TYPE    |INTEGER |0 |10 |10 |NULL  |NULL  |YES 
NAME    |VARCHAR |NULL|NULL|255 |NULL  |510  |NO 
USERNAME   |VARCHAR |NULL|NULL|255 |NULL  |510  |NO 
LIMIT    |DOUBLE |NULL|2 |52 |NULL  |NULL  |YES 
GOAL    |DOUBLE |NULL|2 |52 |NULL  |NULL  |YES 

实体:

现金流

package com.singularityfx.cashelyok.entities; 

import java.time.LocalDate; 

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import javax.persistence.OneToOne; 
import javax.persistence.Transient; 
import javax.validation.constraints.Min; 
import javax.validation.constraints.NotNull; 
import javax.validation.constraints.Size; 

import com.singularityfx.cashelyok.entities.enums.CashFlowType; 

@Entity 
public class CashFlow implements Comparable<CashFlow> { 
    @Id 
    @GeneratedValue 
    private int id; 
    @NotNull @Min(0) 
    private double amount; 
    @Size(max=200) 
    private String description; 
    @NotNull 
    private LocalDate date; 
    @OneToOne @NotNull 
    private CashFlowCategory category; 
    @Transient 
    private boolean editable = false; 

    public CashFlow() {} 

    public CashFlow(
       LocalDate date, 
       CashFlowCategory category, 
       String description, 
       double amount) { 
     this.date = date; 
     this.category = category; 
     this.description = description; 
     this.amount = amount; 
    } 

    public int getId() { 
     return id; 
    } 

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

    public CashFlowType getType() { 
     return category.getType(); 
    } 

    public double getAmount() { 
     return amount; 
    } 

    public void setAmount(double amount) { 
     this.amount = amount; 
    } 

    public LocalDate getDate() { 
     return date; 
    } 

    public void setDate(LocalDate date) { 
     this.date = date; 
    } 

    public CashFlowCategory getCategory() { 
     return category; 
    } 

    public void setCategory(CashFlowCategory category) { 
     this.category = category; 
    } 

    public String getDescription() { 
     return description; 
    } 

    public void setDescription(String description) { 
     this.description = description; 
    } 

    @Column(name="username") 
    public String getUsername() { 
     return category.getPrimaryKey().getUsername(); 
    } 

    public boolean isEditable() { 
     return editable; 
    } 

    public void setEditable(boolean editable) { 
     this.editable = editable; 
    } 

    @Override 
    public String toString() { 
     return "(" + date + "|" + category + "|" + description 
       + "|" + amount + "|" + category.getPrimaryKey().getUsername() + ")"; 
    } 

    @Override 
    public int compareTo(CashFlow o) { 
     return this.getDate().compareTo(o.getDate()); 
    } 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     long temp; 
     temp = Double.doubleToLongBits(amount); 
     result = prime * result + (int) (temp^(temp >>> 32)); 
     result = prime * result 
       + ((category == null) ? 0 : category.hashCode()); 
     result = prime * result + ((date == null) ? 0 : date.hashCode()); 
     result = prime * result 
       + ((description == null) ? 0 : description.hashCode()); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     CashFlow other = (CashFlow) obj; 
     if (Double.doubleToLongBits(amount) != Double 
       .doubleToLongBits(other.amount)) 
      return false; 
     if (category == null) { 
      if (other.category != null) 
       return false; 
     } else if (!category.equals(other.category)) 
      return false; 
     if (date == null) { 
      if (other.date != null) 
       return false; 
     } else if (!date.equals(other.date)) 
      return false; 
     if (description == null) { 
      if (other.description != null) 
       return false; 
     } else if (!description.equals(other.description)) 
      return false; 
     return true; 
    } 
} 

CashFlowCategory

package com.singularityfx.cashelyok.entities; 

import javax.persistence.EmbeddedId; 
import javax.persistence.Entity; 
import javax.persistence.Transient; 
import javax.validation.constraints.Min; 
import javax.validation.constraints.NotNull; 

import com.singularityfx.cashelyok.entities.enums.CashFlowType; 

@Entity 
public class CashFlowCategory implements Comparable<CashFlowCategory> { 
    @EmbeddedId 
    private CashFlowCategoryPK primaryKey; 
    @NotNull 
    private CashFlowType type; 
    @Min(0) 
    private double goal; 
    @Transient 
    public static final String SEPARATOR = " - "; 

    public CashFlowCategory() {} 

    public CashFlowCategory(String name, CashFlowType type, double goal, String username) { 
     this.primaryKey = new CashFlowCategoryPK(name, username); 
     this.type = type; 
     this.goal = goal; 
    } 

    @Override 
    public String toString() { 
     return type + SEPARATOR + primaryKey.getName(); 
    } 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result 
       + ((primaryKey == null) ? 0 : primaryKey.hashCode()); 
     result = prime * result + ((type == null) ? 0 : type.hashCode()); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     CashFlowCategory other = (CashFlowCategory) obj; 
     if (primaryKey == null) { 
      if (other.primaryKey != null) 
       return false; 
     } else if (!primaryKey.equals(other.primaryKey)) 
      return false; 
     if (type != other.type) 
      return false; 
     return true; 
    } 

    @Override 
    public int compareTo(CashFlowCategory o) { 
     /* 
     * To avoid NullPointerException from javax.faces.component.UIInput.compareValues 
     * when adding new cash flow via cash flows page after attempting to add 
     * cash flow without filling all mandatory fields 
     */ 
     if (type == null) { 
      return -1; 
     } 

     int returnValue = type.compareTo(o.getType()); 
     if (returnValue == 0) { 
      returnValue = primaryKey.getName().compareTo(o.getName()); 
     } 
     return returnValue; 
    } 

    public CashFlowCategoryPK getPrimaryKey() { 
     return primaryKey; 
    } 

    public void setPrimaryKey(CashFlowCategoryPK primaryKey) { 
     this.primaryKey = primaryKey; 
    } 

    public String getName() { 
     return primaryKey.getName(); 
    } 

    public CashFlowType getType() { 
     return type; 
    } 

    public String getUsername() { 
     return primaryKey.getUsername(); 
    } 

    public double getGoal() { 
     return goal; 
    } 

    public void setGoal(double goal) { 
     this.goal = goal; 
    } 
} 

CashFlowCategoryPK(嵌入式ID)

package com.singularityfx.cashelyok.entities; 

import java.io.Serializable; 

import javax.persistence.Column; 
import javax.persistence.Embeddable; 
import javax.validation.constraints.NotNull; 
import javax.validation.constraints.Size; 

@Embeddable 
public class CashFlowCategoryPK implements Serializable { 
    private static final long serialVersionUID = 392533037882395947L; 
    @NotNull @Size(min=1, max=200) 
    @Column(name="NAME") 
    private String name; 
    @NotNull @Size(min=1, max=200) 
    @Column(name="USERNAME") 
    private String username; 

    public CashFlowCategoryPK() { 
    } 

    public CashFlowCategoryPK(String name, String username) { 
     this.name = name; 
     this.username = username; 
    } 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + ((name == null) ? 0 : name.hashCode()); 
     result = prime * result 
       + ((username == null) ? 0 : username.hashCode()); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     CashFlowCategoryPK other = (CashFlowCategoryPK) obj; 
     if (name == null) { 
      if (other.name != null) 
       return false; 
     } else if (!name.equals(other.name)) 
      return false; 
     if (username == null) { 
      if (other.username != null) 
       return false; 
     } else if (!username.equals(other.username)) 
      return false; 
     return true; 

    } 
    public String getName() { 
     return name; 
    } 

    public String getUsername() { 
     return username; 
    } 
} 

堆栈跟踪:

org.hibernate.HibernateException: Missing column: category_NAME in .APP.CASHFLOW 
    at org.hibernate.mapping.Table.validateColumns(Table.java:366) 
    at org.hibernate.cfg.Configuration.validateSchema(Configuration.java:1338) 
    at org.hibernate.tool.hbm2ddl.SchemaValidator.validate(SchemaValidator.java:175) 
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:525) 
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1859) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850) 
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849) 
    at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:152) 
    at org.glassfish.persistence.jpa.PersistenceUnitLoader.loadPU(PersistenceUnitLoader.java:199) 
    at org.glassfish.persistence.jpa.PersistenceUnitLoader.<init>(PersistenceUnitLoader.java:107) 
    at org.glassfish.persistence.jpa.JPADeployer$1.visitPUD(JPADeployer.java:223) 
    at org.glassfish.persistence.jpa.JPADeployer$PersistenceUnitDescriptorIterator.iteratePUDs(JPADeployer.java:510) 
    at org.glassfish.persistence.jpa.JPADeployer.createEMFs(JPADeployer.java:230) 
    at org.glassfish.persistence.jpa.JPADeployer.prepare(JPADeployer.java:168) 
    at com.sun.enterprise.v3.server.ApplicationLifecycle.prepareModule(ApplicationLifecycle.java:922) 
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:431) 
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219) 
    at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491) 
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:527) 
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:523) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at javax.security.auth.Subject.doAs(Subject.java:360) 
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:522) 
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:546) 
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1423) 
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1500(CommandRunnerImpl.java:108) 
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1762) 
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1674) 
    at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:534) 
    at com.sun.enterprise.v3.admin.AdminAdapter.onMissingResource(AdminAdapter.java:224) 
    at org.glassfish.grizzly.http.server.StaticHttpHandler.service(StaticHttpHandler.java:297) 
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:246) 
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191) 
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168) 
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189) 
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114) 
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) 
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838) 
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113) 
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115) 
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55) 
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135) 
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564) 
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544) 
    at java.lang.Thread.run(Thread.java:745)]] 

的persistence.xml

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.1" 
xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> 
    <persistence-unit name="cashelyok" transaction-type="JTA"> 
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> 
    <jta-data-source>cashelyok-resource</jta-data-source> 
    <properties> 
     <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" /> 
     <property name="hibernate.hbm2ddl.auto" value="validate" /> 
    </properties> 
    </persistence-unit> 
</persistence> 

回答

1

就像你说的,你明白告诉Hibernate来地图CashFlowCategoryPKname字段到NAME列;但是错误实际上是关于Hibernate寻找CashFlow的表.APP.CASHFLOW中的联接(外键)列category_NAME。这是因为您没有在CashFlowcategory字段中指定加入列。

根据JPA规范,默认连接键列名称的格式为<ref_field_name>_<pk_column_name>(在您的情况下,它将为category_NAME;因此为错误消息)。我猜EclipseLink比规范要求的默认值多一点。要解决此问题,您需要明确指定CashFlow中的连接列:

@OneToOne 
@NotNull 
@JoinColumns({ 
    @JoinColumn(name="NAME", referencedColumnName="NAME"), 
    @JoinColumn(name="USERNAME", referencedColumnName="USERNAME") 
}) 
private CashFlowCategory category;