使用 JPQL 查询使用 UCanAccess 驱动程序的 MS-Access 数据库
Using JPQL for queries to an MS-Access database using UCanAccess driver
使用时
- JPA 2.1
- EclipseLink 2.5.2
- UCanAccess 4.0.4
我们遇到的问题是 tables 将用引号命名。这是因为底层实现并不真正知道要使用哪种方言,导致与 MSAccess 不兼容。这会导致例如table 注释如 @Table(name = "\"EMPLOYEE\"")
.
为了解决这个问题,我们必须在 orm.xml 中包含:
...
<persistence-unit-defaults>
<delimited-identifiers />
</persistence-unit-defaults>
...
现在普通查询可以工作,但在命名查询中使用 JPQL 将失败,因为生成的 SQL 查询将引用所有列名:
[EL Warning]: 2019-06-02 21:14:27.818--UnitOfWork(2144282958)--Thread(Thread[main,5,main])--Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: net.ucanaccess.jdbc.UcanaccessSQLException: UCAExc:::4.0.4 unexpected token: Personen
Error Code: -5581
Call: SELECT "PersonId", "EMail", "Ansprechpartner", "Briefanrede", "Fax", "Name", "Ort", "PLZ", "Sortierung", "Straße", "Telefon" FROM "Personen"
Query: ReadAllQuery(name="Personen.findAll" referenceClass=Personen sql="SELECT "PersonId", "EMail", "Ansprechpartner", "Briefanrede", "Fax", "Name", "Ort", "PLZ", "Sortierung", "Straße", "Telefon" FROM "Personen"")
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:682)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558)
at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2002)
at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:570)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelectCall(DatasourceCallQueryMechanism.java:299)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectAllRows(DatasourceCallQueryMechanism.java:694)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRowsFromTable(ExpressionQueryMechanism.java:2738)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2691)
at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:495)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1168)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1127)
at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:403)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1215)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1751)
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258)
at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:469)
at de.mebrach.jungebuehne.vorverkauf.PersonenService.loadAll(PersonenService.java:20)
at Main.main(Main.java:20)
Caused by: net.ucanaccess.jdbc.UcanaccessSQLException: UCAExc:::4.0.4 unexpected token: Personen
在 persistence.xml 中包含一个 trget-database 属性:
<property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.AccessPlatformDelimiterConfig"/>
向 class 路径添加一个新的 class:
package org.eclipse.persistence.platform.database;
public class AccessPlatformDelimiterConfig extends AccessPlatform {
private static final long serialVersionUID = 7034590043310425678L;
public AccessPlatformDelimiterConfig() {
super();
this.tableQualifier = "";
this.startDelimiter = "[";
this.endDelimiter = "]";
}
}
使用时
- JPA 2.1
- EclipseLink 2.5.2
- UCanAccess 4.0.4
我们遇到的问题是 tables 将用引号命名。这是因为底层实现并不真正知道要使用哪种方言,导致与 MSAccess 不兼容。这会导致例如table 注释如 @Table(name = "\"EMPLOYEE\"")
.
为了解决这个问题,我们必须在 orm.xml 中包含:
...
<persistence-unit-defaults>
<delimited-identifiers />
</persistence-unit-defaults>
...
现在普通查询可以工作,但在命名查询中使用 JPQL 将失败,因为生成的 SQL 查询将引用所有列名:
[EL Warning]: 2019-06-02 21:14:27.818--UnitOfWork(2144282958)--Thread(Thread[main,5,main])--Local Exception Stack: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: net.ucanaccess.jdbc.UcanaccessSQLException: UCAExc:::4.0.4 unexpected token: Personen Error Code: -5581 Call: SELECT "PersonId", "EMail", "Ansprechpartner", "Briefanrede", "Fax", "Name", "Ort", "PLZ", "Sortierung", "Straße", "Telefon" FROM "Personen" Query: ReadAllQuery(name="Personen.findAll" referenceClass=Personen sql="SELECT "PersonId", "EMail", "Ansprechpartner", "Briefanrede", "Fax", "Name", "Ort", "PLZ", "Sortierung", "Straße", "Telefon" FROM "Personen"") at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340) at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:682) at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558) at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2002) at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:570) at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242) at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228) at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelectCall(DatasourceCallQueryMechanism.java:299) at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectAllRows(DatasourceCallQueryMechanism.java:694) at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRowsFromTable(ExpressionQueryMechanism.java:2738) at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2691) at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:495) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1168) at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899) at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1127) at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:403) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1215) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1751) at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258) at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:469) at de.mebrach.jungebuehne.vorverkauf.PersonenService.loadAll(PersonenService.java:20) at Main.main(Main.java:20) Caused by: net.ucanaccess.jdbc.UcanaccessSQLException: UCAExc:::4.0.4 unexpected token: Personen
在 persistence.xml 中包含一个 trget-database 属性:
<property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.AccessPlatformDelimiterConfig"/>
向 class 路径添加一个新的 class:
package org.eclipse.persistence.platform.database;
public class AccessPlatformDelimiterConfig extends AccessPlatform {
private static final long serialVersionUID = 7034590043310425678L;
public AccessPlatformDelimiterConfig() {
super();
this.tableQualifier = "";
this.startDelimiter = "[";
this.endDelimiter = "]";
}
}