Eclipselink искажен динамический запрос левого внешнего соединения - PullRequest
0 голосов
/ 19 ноября 2018

Есть две сущности Персона и Адрес.Существует отношение 1: M от человека к адресу.(Предполагается, что человек имеет временный и постоянный адрес).

Ключевые свойства класса Person:

  1. personId (pk)
  2. пол

Ключевые свойства класса Address:

  1. addressId (pk)
  2. personId (fk)
  3. пол

Ниже приведен фрагмент кода дескриптора для классов Person и Address:

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 ;

Как написать выражение для добавления полового условия (тип данных char в db) в самом первом предложении соединения и избавиться от второго предложения соединения?

Ожидаемый запрос: SELECT t0.PID, COUNT (t1.AID) ОТ ЧЕЛОВЕКА t0 ВЛЕВО НАРУЖНЫЙ АДРЕС СОЕДИНЕНИЯ t1 ВКЛ (t1.PID = t0.PID AND (t2.gender = 'M')) WHERE t0.gender = 'M' GROUP BY t0.PID

1 Ответ

0 голосов
/ 20 ноября 2018

У вас есть два отдельных объединения, потому что вы вызываете и используете 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 приведет к тому, что соединение будет создано только один раз, а другие пути будут построены из него вместо нового.

...