2013-04-27 13 views
6

我希望我只是在做一些愚蠢的在這裏...的EclipseLink JPA「無效的表在這方面」與@OneToMany地圖

我試圖建立JPA註解爲Map<String, Phone>和獲取跟蹤堆棧跟蹤。

Exception [EclipseLink-6069] (Eclipse Persistence Services - 2.4.1.v20121003-ad44345): org.eclipse.persistence.exceptions.QueryException 
Exception Description: The field [EMPLOYEE.PHONE_TYPE] in this expression has an invalid table in this context. 
Query: ReadAllQuery(name="phones" referenceClass=Phone) 
    at org.eclipse.persistence.exceptions.QueryException.invalidTableForFieldInExpression(QueryException.java:739) 
    at org.eclipse.persistence.internal.expressions.FieldExpression.validateNode(FieldExpression.java:281) 
    at org.eclipse.persistence.expressions.Expression.normalize(Expression.java:3259) 
    at org.eclipse.persistence.internal.expressions.DataExpression.normalize(DataExpression.java:369) 
    at org.eclipse.persistence.internal.expressions.FieldExpression.normalize(FieldExpression.java:208) 
    at org.eclipse.persistence.internal.expressions.SQLSelectStatement.normalize(SQLSelectStatement.java:1377) 
    at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.buildNormalSelectStatement(ExpressionQueryMechanism.java:546) 
    at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.prepareSelectAllRows(ExpressionQueryMechanism.java:1700) 
    at org.eclipse.persistence.queries.ReadAllQuery.prepareSelectAllRows(ReadAllQuery.java:721) 
    at org.eclipse.persistence.queries.ReadAllQuery.prepare(ReadAllQuery.java:657) 
    at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:614) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:883) 
    at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:575) 
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:820) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1109) 
    at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:393) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1197) 
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2875) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1602) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1584) 
    at org.eclipse.persistence.internal.indirection.QueryBasedValueHolder.instantiate(QueryBasedValueHolder.java:112) 
    at org.eclipse.persistence.internal.indirection.QueryBasedValueHolder.instantiate(QueryBasedValueHolder.java:99) 
    at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:88) 
    at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiateImpl(UnitOfWorkValueHolder.java:161) 
    at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:222) 
    at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:88) 
    at org.eclipse.persistence.indirection.IndirectMap.buildDelegate(IndirectMap.java:110) 
    at org.eclipse.persistence.indirection.IndirectMap.getDelegate(IndirectMap.java:330) 
    at org.eclipse.persistence.indirection.IndirectMap.size(IndirectMap.java:637) 
    at org.eclipse.persistence.internal.queries.MapContainerPolicy.sizeFor(MapContainerPolicy.java:830) 
    at org.eclipse.persistence.internal.indirection.TransparentIndirectionPolicy.instantiateObject(TransparentIndirectionPolicy.java:386) 
    at org.eclipse.persistence.mappings.ForeignReferenceMapping.buildCloneFromRow(ForeignReferenceMapping.java:285) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoWorkingCopyClone(ObjectBuilder.java:1594) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuilder.java:1741) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:668) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:605) 
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:564) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:777) 
    at org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:783) 
    at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:434) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1150) 
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:852) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1109) 
    at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:393) 
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1197) 
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2875) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1602) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1584) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1549) 
    at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:231) 
    at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:411) 
    at aaa.Test.main(Test.java:20) 

創建的表如下所示:

EMP_PHONE 
================================= 
EMP_ID PHONES_ID PHONE_TYPE 
------ --------- ---------- 
42  1   NULL 


EMPLOYEE 
================================= 
ID 
-- 
42 


PHONE 
================================= 
ID NUM 
-- -------- 
1  867-5309 

NULLPHONE_TYPE似乎在告訴我一些時髦是怎麼回事,和的EclipseLink正在尋找EMPLOYEE.PHONE_TYPE的方式讓我覺得它是思考的關係從PHONE - >EMPLOYEE而不是其他方式。

JPA實體定義如下。手機地圖是單向的,而電話對象應該由多個員工共享(不是我的實際類型,但這種簡化的示例演示了此問題),使用下面的測試代碼

EntityManagerFactory factory = Persistence.createEntityManagerFactory("test"); 
EntityManager em = factory.createEntityManager(); 
Employee employee = new Employee(42); 
// exception will occur with or without phones added to the map 
employee.getPhones().put("home", new Phone(1, "867-5309")); 
em.getTransaction().begin(); 
em.persist(employee); 
em.getTransaction().commit(); 

Query q = em.createQuery("select o from Employee o"); 
q.setHint("javax.persistence.cache.storeMode", "REFRESH"); 
q.getResultList(); // EXCEPTION THROWN HERE 

和持久性

@Entity 
public class Employee { 
    @Id private long id; 

    @OneToMany(cascade=CascadeType.ALL) 
    @JoinTable(name="EMP_PHONE", [email protected](name="EMP_ID")) 
    @MapKeyColumn(name="PHONE_TYPE") 
    private Map<String, Phone> phones = new HashMap<String, Phone>(); 

    public Employee() {} 
    public Employee(long id) { 
     this.id = id; 
    } 
    public long getId() { 
     return id; 
    } 
    public Map<String, Phone> getPhones() { 
     return phones; 
    } 
} 

@Entity 
public class Phone { 
    @Id 
    private long id; 
    private String num; 

    public String getNum() { 
     return num; 
    } 
    public Phone() {} 
    public Phone(String num) { 
     this.num = num; 
    } 
    public Phone(long id, String num) { 
     this.id = id; 
     this.num = num; 
    } 
    public long getId() { 
     return id; 
    } 
} 

.xml:

<?xml version='1.0' encoding='UTF-8' ?> 
<persistence xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
    xsi:schemaLocation='http://java.sun.com/xml/ns/persistence 
      http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd' 
    version='2.0' xmlns='http://java.sun.com/xml/ns/persistence'> 
    <persistence-unit name='test' transaction-type='RESOURCE_LOCAL'> 
     <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 
     <class>aaa.Phone</class> 
     <class>aaa.Employee</class> 
     <shared-cache-mode>NONE</shared-cache-mode> 
     <properties> 
      <property name='javax.persistence.jdbc.user' value='uuuuuuuu' /> 
      <property name='javax.persistence.jdbc.password' value='pppppppp' /> 
      <property name='javax.persistence.jdbc.driver' 
         value='oracle.jdbc.driver.OracleDriver' /> 
      <property name='javax.persistence.jdbc.url' 
         value='jdbc:oracle:thin:@localhost:1521:xe' /> 
      <property name='eclipselink.ddl-generation' 
         value='drop-and-create-tables' /> 
      <property name='eclipselink.ddl-generation.output-mode' value='database' /> 
     </properties> 
    </persistence-unit> 
</persistence> 

我在Windows 7上運行,使用Oracle XE 11g作爲數據庫。預先感謝任何見解!

回答

10

這看起來像EclipseLink的錯誤364922

An entity with uni-directional OneToMany property and @MapKeyColumn annotation has the correct database tables created, with the mapping table containing a "key column, but persisting an entity only populates the id columns and not the key column. The persist operation does not throw an error, but subsequent queries soon fail with the following error: Exception Description: The field [ORGANIZATION.MAILINGADDRESSES_KEY] in this expression has an invalid table in this context.

對於它的價值,我測試使用Hibernate/H2你的代碼,它工作正常。

UPDATE

我只是測試的EclipseLink此。如果您明確設置了MapKeyColumn的表格,則密鑰正確填充。即:

@MapKeyColumn(name="PHONE_TYPE", table="EMP_PHONE")

+0

非常感謝!我認爲這是我沒有嘗試的選項的組合之一;)希望我在搜索時看到了這個錯誤。 – 2013-04-30 21:25:38

+0

我在我的真實應用程序中測試過它,它完美地工作。再次感謝 – 2013-04-30 22:10:38

+0

很高興幫助。我已經遇到了我在JPA實現中難以解決的問題,我知道它們可以使你瘋狂;) – pwrex 2013-05-01 04:44:59