Eclipselink 左外连接动态查询格式错误
Eclipselink left outer join dynamic query malformed
有两个实体 Person 和 Address。从 Person 到 Address 存在 1:M 关系。 (假设一个人有临时地址和永久地址)。
Person class 的关键属性是:
- personId(pk)
- 性别
Address class 的关键属性是:
- addressId(pk)
- personId(fk)
- 性别
以下是 Person 和 Address classes 的描述符代码片段:
public RelationalDescriptor buildPersonDescriptor() {
RelationalDescriptor descriptor = new RelationalDescriptor();
descriptor.setJavaClass(Person.class);
descriptor.addTableName("PERSON");
descriptor.addPrimaryKeyFieldName("PERSON.PID");
// RelationalDescriptor properties.
descriptor.useSoftCacheWeakIdentityMap();
descriptor.setIdentityMapSize(100);
descriptor.useRemoteSoftCacheWeakIdentityMap();
descriptor.setRemoteIdentityMapSize(100);
descriptor.setSequenceNumberFieldName("PERSON.PID");
descriptor.setSequenceNumberName("PERSON_SEQ");
descriptor.setAlias("person");
// Query manager.
descriptor.getDescriptorQueryManager().checkCacheForDoesExist();
descriptor.getDescriptorQueryManager().setAdditionalJoinExpression(new ExpressionBuilder().get("gender").equal('N'));
// Query manager.
// Mappings.
DirectToFieldMapping pIDMapping = new DirectToFieldMapping();
pIDMapping.setAttributeName("personId");
pIDMapping.setFieldName("PERSON.PID");
descriptor.addMapping(pIDMapping);
DirectToFieldMapping genderMapping = new DirectToFieldMapping();
genderMapping.setAttributeName("gender");
genderMapping.setFieldName("PERSON.GENDER");
descriptor.addMapping(genderMapping);
OneToManyMapping addressMapping = new OneToManyMapping();
addressMapping.setAttributeName("address");
addressMapping.setReferenceClass(Address.class);
addressMapping.useTransparentCollection();
addressMapping.useCollectionClass(IndirectList.class);
addressMapping.addTargetForeignKeyFieldName("ADDRESS.PID", "PERSON.PID");
descriptor.addMapping(addressMapping);
return descriptor;
}
public RelationalDescriptor buildAddressDescriptor() {
RelationalDescriptor descriptor = new RelationalDescriptor();
descriptor.setJavaClass(com.tropics.application.products.domain.costingandpricing.SellingPriceAddOn.class);
descriptor.addTableName("ADDRESS");
descriptor.addPrimaryKeyFieldName("ADDRESS.AID");
// Descriptor properties.
descriptor.useSoftCacheWeakIdentityMap();
descriptor.setIdentityMapSize(100);
descriptor.useRemoteSoftCacheWeakIdentityMap();
descriptor.setRemoteIdentityMapSize(100);
descriptor.setSequenceNumberFieldName("ADDRESS.AID");
descriptor.setSequenceNumberName("ADDRESS_SEQ");
descriptor.setAlias("address");
// Query manager.
descriptor.getDescriptorQueryManager().checkCacheForDoesExist();
//Mappings
DirectToFieldMapping genderMapping = new DirectToFieldMapping();
genderMapping.setAttributeName("gender");
genderMapping.setFieldName("ADDRESS.GENDER");
descriptor.addMapping(genderMapping);
DirectToFieldMapping personIDMapping = new DirectToFieldMapping();
personIDMapping.setAttributeName("personId");
personIDMapping.setFieldName("ADDRESS.PID");
descriptor.addMapping(personIDMapping);
DirectToFieldMapping addressIDMapping = new DirectToFieldMapping();
addressIDMapping.setAttributeName("addressId");
addressIDMapping.setFieldName("ADDRESS.AID");
descriptor.addMapping(addressIDMapping);
}
以下是生成动态查询的代码片段:
ExpressionBuilder expBuilder = new ExpressionBuilder();
ReportQuery query = new ReportQuery(Person.class, expBuilder);
//Getting the MVSelling DetailsID and the number of Selling price add ons for each of them
query.addAttribute("personId", expBuilder.get("personId"));
query.addAttribute
("addressCounter", expBuilder.anyOfAllowingNone("address").get("addressId").count());
Expression addressExp = expBuilder.anyOfAllowingNone("address");
expBuilder.leftJoin(addressExp, addressExp.get("gender").equal('M'));
query.addNonFetchJoin(addressExp);
query.addGrouping("personId");
resultCollection = (Vector)clientSessionHolder.eclipselinkClientSession().executeQuery(query);
在 运行 这个程序上,根据日志生成的查询:
SELECT t0.PID, COUNT(t1.AID)
FROM PERSON t0 LEFT OUTER JOIN ADDRESS t1
ON (t1.PID = t0.PID)
LEFT OUTER JOIN ADDRESS t2
ON ((t2.PID = t0.PID)
AND (t2.gender = 'M'))
WHERE (t0.gender = 'M')) GROUP BY t0.PID ;
如何编写表达式以在第一个连接子句本身中添加性别条件(db 中的 char 数据类型)并摆脱第二个连接子句?
预期的查询是:
SELECT t0.PID, 计数(t1.AID)
FROM PERSON t0 左外连接地址 t1
打开(t1.PID = t0.PID 和(t2.gender = 'M'))
其中 t0.gender = 'M' 按 t0.PID
分组
您有两个单独的联接,因为您在表达式中调用并使用了 expBuilder.anyOfAllowingNone("address") 两次。 anyOfAllowingNone
告诉 EclipseLink 在该关系上创建一个外部连接,并将其用作从该关系构建的表达式的基础。
尝试
Expression addressExp = expBuilder.anyOfAllowingNone("address");
query.addAttribute("addressCounter", addressExp.get("addressId").count());
expBuilder.leftJoin(addressExp, addressExp.get("gender").equal('M'));
query.addNonFetchJoin(addressExp);
重复使用 addressExp 将导致仅创建一次连接,并根据它构建其他路径而不是新路径。
有两个实体 Person 和 Address。从 Person 到 Address 存在 1:M 关系。 (假设一个人有临时地址和永久地址)。
Person class 的关键属性是:
- personId(pk)
- 性别
Address class 的关键属性是:
- addressId(pk)
- personId(fk)
- 性别
以下是 Person 和 Address classes 的描述符代码片段:
public RelationalDescriptor buildPersonDescriptor() {
RelationalDescriptor descriptor = new RelationalDescriptor();
descriptor.setJavaClass(Person.class);
descriptor.addTableName("PERSON");
descriptor.addPrimaryKeyFieldName("PERSON.PID");
// RelationalDescriptor properties.
descriptor.useSoftCacheWeakIdentityMap();
descriptor.setIdentityMapSize(100);
descriptor.useRemoteSoftCacheWeakIdentityMap();
descriptor.setRemoteIdentityMapSize(100);
descriptor.setSequenceNumberFieldName("PERSON.PID");
descriptor.setSequenceNumberName("PERSON_SEQ");
descriptor.setAlias("person");
// Query manager.
descriptor.getDescriptorQueryManager().checkCacheForDoesExist();
descriptor.getDescriptorQueryManager().setAdditionalJoinExpression(new ExpressionBuilder().get("gender").equal('N'));
// Query manager.
// Mappings.
DirectToFieldMapping pIDMapping = new DirectToFieldMapping();
pIDMapping.setAttributeName("personId");
pIDMapping.setFieldName("PERSON.PID");
descriptor.addMapping(pIDMapping);
DirectToFieldMapping genderMapping = new DirectToFieldMapping();
genderMapping.setAttributeName("gender");
genderMapping.setFieldName("PERSON.GENDER");
descriptor.addMapping(genderMapping);
OneToManyMapping addressMapping = new OneToManyMapping();
addressMapping.setAttributeName("address");
addressMapping.setReferenceClass(Address.class);
addressMapping.useTransparentCollection();
addressMapping.useCollectionClass(IndirectList.class);
addressMapping.addTargetForeignKeyFieldName("ADDRESS.PID", "PERSON.PID");
descriptor.addMapping(addressMapping);
return descriptor;
}
public RelationalDescriptor buildAddressDescriptor() {
RelationalDescriptor descriptor = new RelationalDescriptor();
descriptor.setJavaClass(com.tropics.application.products.domain.costingandpricing.SellingPriceAddOn.class);
descriptor.addTableName("ADDRESS");
descriptor.addPrimaryKeyFieldName("ADDRESS.AID");
// Descriptor properties.
descriptor.useSoftCacheWeakIdentityMap();
descriptor.setIdentityMapSize(100);
descriptor.useRemoteSoftCacheWeakIdentityMap();
descriptor.setRemoteIdentityMapSize(100);
descriptor.setSequenceNumberFieldName("ADDRESS.AID");
descriptor.setSequenceNumberName("ADDRESS_SEQ");
descriptor.setAlias("address");
// Query manager.
descriptor.getDescriptorQueryManager().checkCacheForDoesExist();
//Mappings
DirectToFieldMapping genderMapping = new DirectToFieldMapping();
genderMapping.setAttributeName("gender");
genderMapping.setFieldName("ADDRESS.GENDER");
descriptor.addMapping(genderMapping);
DirectToFieldMapping personIDMapping = new DirectToFieldMapping();
personIDMapping.setAttributeName("personId");
personIDMapping.setFieldName("ADDRESS.PID");
descriptor.addMapping(personIDMapping);
DirectToFieldMapping addressIDMapping = new DirectToFieldMapping();
addressIDMapping.setAttributeName("addressId");
addressIDMapping.setFieldName("ADDRESS.AID");
descriptor.addMapping(addressIDMapping);
}
以下是生成动态查询的代码片段:
ExpressionBuilder expBuilder = new ExpressionBuilder();
ReportQuery query = new ReportQuery(Person.class, expBuilder);
//Getting the MVSelling DetailsID and the number of Selling price add ons for each of them
query.addAttribute("personId", expBuilder.get("personId"));
query.addAttribute
("addressCounter", expBuilder.anyOfAllowingNone("address").get("addressId").count());
Expression addressExp = expBuilder.anyOfAllowingNone("address");
expBuilder.leftJoin(addressExp, addressExp.get("gender").equal('M'));
query.addNonFetchJoin(addressExp);
query.addGrouping("personId");
resultCollection = (Vector)clientSessionHolder.eclipselinkClientSession().executeQuery(query);
在 运行 这个程序上,根据日志生成的查询:
SELECT t0.PID, COUNT(t1.AID)
FROM PERSON t0 LEFT OUTER JOIN ADDRESS t1
ON (t1.PID = t0.PID)
LEFT OUTER JOIN ADDRESS t2
ON ((t2.PID = t0.PID)
AND (t2.gender = 'M'))
WHERE (t0.gender = 'M')) GROUP BY t0.PID ;
如何编写表达式以在第一个连接子句本身中添加性别条件(db 中的 char 数据类型)并摆脱第二个连接子句?
预期的查询是: SELECT t0.PID, 计数(t1.AID) FROM PERSON t0 左外连接地址 t1 打开(t1.PID = t0.PID 和(t2.gender = 'M')) 其中 t0.gender = 'M' 按 t0.PID
分组您有两个单独的联接,因为您在表达式中调用并使用了 expBuilder.anyOfAllowingNone("address") 两次。 anyOfAllowingNone
告诉 EclipseLink 在该关系上创建一个外部连接,并将其用作从该关系构建的表达式的基础。
尝试
Expression addressExp = expBuilder.anyOfAllowingNone("address");
query.addAttribute("addressCounter", addressExp.get("addressId").count());
expBuilder.leftJoin(addressExp, addressExp.get("gender").equal('M'));
query.addNonFetchJoin(addressExp);
重复使用 addressExp 将导致仅创建一次连接,并根据它构建其他路径而不是新路径。