EclipseLink JPA "Invalid table in this context" with @OneToMany Map

I hope that I'm just doing something stupid here ...

I am trying to configure JPA annotations for Map<String, Phone> and get the next stack trace.

 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) 

The created tables are as follows:

 EMP_PHONE ================================= EMP_ID PHONES_ID PHONE_TYPE ------ --------- ---------- 42 1 NULL EMPLOYEE ================================= ID -- 42 PHONE ================================= ID NUM -- -------- 1 867-5309 

NULL PHONE_TYPE seems to be telling me that something scary is happening, and the way eclipselink is looking for EMPLOYEE.PHONE_TYPE makes me think about the relationship between PHONEEMPLOYEE , and not vice versa.

JPA entities are defined as follows. The phone map is unidirectional, and Phone objects must be shared by several people (not my actual types, but this simplified example demonstrates the problem).

 @Entity public class Employee { @Id private long id; @OneToMany(cascade=CascadeType.ALL) @JoinTable(name="EMP_PHONE", joinColumns=@JoinColumn (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; } } 

using the following test code

 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 

and persistence.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> 

I am working on Windows 7 using Oracle XE 11g as a database. Thank you in advance for any ideas!

+6
source share
1 answer

This looks like EclipseLink 364922 error:

An entity with the OneToMany unidirectional property and @MapKeyColumn annotation has the correct database tables created with a mapping table containing a "key column", but saving the object only fills the identifier columns, not the key columns. does not throw an error, but subsequent queries soon fail with the following error: Exception Description: The [ORGANIZATION.MAILINGADDRESSES_KEY] field in this expression has an invalid table in this context.

For what it's worth, I checked your code with Hibernate / H2 and it works great.

UPDATE

I just checked this with EclipseLink. If you explicitly set a table for MapKeyColumn , the key is populated correctly. i.e:.

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

+10
source

Source: https://habr.com/ru/post/943763/


All Articles