EntityFieldQuery와 함께 OR 사용


26

오늘 전에이 작업을 수행 할 필요가 없었지만 select 쿼리에 사용 EntityFieldQuery되기 때문에 OR 쿼리를 수행 할 수있는 것처럼 보이지 않습니다 db_or.

예를 들어 값이 null이거나 오늘 이후 인 날짜 필드가있는 모든 엔티티에 도달합니다.

무언가 또는 일부 트릭이 누락되었거나 단순히 지원되지 않습니까?


하나의 쿼리를 두 개로 분할하여 실행 한 다음 결과를 결합 할 수도 있습니다.
Vadym Myrgorod

쿼리 나 데이터의 양이 원격으로 더 커지면 이로 인한 성능 영향은 상당히 끔찍합니다.
Tommi Forsström

1
이것은 Google 검색 결과에서 오래되었지만 높았습니다. Drupal 8에서 orConditionGroup을 사용할 수 있습니다.
ognockocaten

답변:


22

나는 이 문제해결책을 보았다 . 좋은 오래된 객체 가 addTag()있는 query and implement 에 사용하는 것이 좋습니다 .hook_query_TAG_alter()SelectQuery


나는 이것을 정답으로 선택할 것을 제안합니다. 블로그 게시물은 EntityFieldQueries에 OR 조건을 추가하는 방법을 제공합니다. 유일한 문제는 실제로 EFQ의 요점과는 달리 해당 방법으로 SQL 종속성을 작성하지만 최소한 작업을 완료한다는 것입니다. 좋은 링크 @ Michael에 감사드립니다.
Tommi Forsström

2
이것은 커뮤니티 답변이며 대부분 외부 링크로 구성되어 있으므로 코드 또는 기사의 일부 내용 이이 답변에 포함되어야한다고 생각합니다. 링크가 죽기 때문입니다. 이 주제에 관한 Meta StackExchange 토론
D. Visser

원래 기사는 다소 길며 아이디어는 "조회에서 addTag () 사용 및 hook_query_TAG_alter () 구현"으로 요약 될 수 있습니다. 그 후 질문은 알려진 주제 인 "SelectQuery 객체와 함께 OR을 사용하는 방법"으로 축소되었습니다.
Michael

이 시나리오에서는 EFQ를 일반 선택 쿼리로 변환하는 것이 좋습니다. EFQ를 고수하고 태그 기반 변경을 사용하여 생성되는 것을 혼란스럽게 만드는 것은 비교할 때 끔찍합니다.

12

EntityFieldQuery몇 가지 방법을 소책자 로 덮어 쓸 수 있습니다 .

클래스 객체에 추가 된 조건 EntityFieldQuery(예 : 속성 조건)이 배열에 추가됩니다.

  public function propertyCondition($column, $value, $operator = NULL) {
    // The '!=' operator is deprecated in favour of the '<>' operator since the
    // latter is ANSI SQL compatible.
    if ($operator == '!=') {
      $operator = '<>';
    }
    $this->propertyConditions[] = array(
      'column' => $column, 
      'value' => $value, 
      'operator' => $operator,
    );
    return $this;
  }

쿼리가 작성되면 해당 배열은 다음과 유사한 루프에서 사용됩니다 (코드는 EntityFieldQuery :: propertyQuery ()에 있음 ).

foreach ($this->propertyConditions as $property_condition) {
  $this->addCondition($select_query, "$base_table." . $property_condition['column'], $property_condition);
}

$select_query에 대한 호출에서 반환 된 값을 포함합니다 db_select().


5

당신은 두려워 할 수 없습니다. OR은 EntityFieldQuery수업에서 기본적으로 지원되지 않습니다 .

한 가지 방법은 with로 쿼리에 태그를 추가 한 ->addTag()다음 hook_query_TAG_alter()해당 태그가 포함 된 쿼리에 대해 쿼리의 내부 구조를 수동으로 변경하도록 구현 하는 것입니다.

이렇게하면 기존 조건을 반복하고 OR논리 를 추가하기 위해 필요한 변경을 수행 할 수 있습니다 . 하지만 그렇게하는 것은 좋은 방법이 아닙니다. 여기서 예 를 찾을 수 있습니다 .


5

쿼리를 2로 나누고 병합하는 등의 작업이 필요 없습니다. 검색어를 변경하면됩니다.

시나리오를 고려하십시오 : 나는 기계 이름을 가진 2 개의 엔티티 유형을 가지고 있습니다 : tincan 문과 tincan_agents

엔티티의 5 개의 엔티티 참조 필드

그 중 4 개는 일반 엔티티 참조 필드이고 5 번째 (tincan_object)는 다중 엔티티 유형 참조 필드이며 각 참조 필드는 'Agent'유형의 엔티티를 참조합니다.

tincan_object 참조 필드는 에이전트 및 활동 (제 3 엔티티 유형)을 참조 할 수 있습니다. 에이전트는 object_type 속성을 가지며 에이전트 또는 그룹 일 수 있습니다.

참조 필드 중 하나에서 가능한 여러 에이전트 중 하나를 참조하는 명령문을 찾고 싶습니다. fieldConditions 사이에 OR 연산자가 필요하지만 다중 엔티티 유형 참조 필드의 object_type을 확인하고 두 가지 가능성 중 하나인지 확인해야합니다.

아래 코드는 가능한 가장 간단한 것을 나타냅니다. 우리 솔루션에서 쿼리에는 다른 많은 조건, 필드 등이 있었으므로 코드는 조건의 순서를 계산하지 않거나 이러한 필드가 모두 쿼리 된 경우에도 필요했습니다.

    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'tincan_statement');

    $all_agents = array(4,10); //entity_ids to search for
    $query->addTag('tincan_statement_get_agents');
    $query->fieldCondition('tincan_actor', 'target_id', $all_agents, 'IN'); 
    //need OR between fields conditions
    $query->fieldCondition('tincan_authority', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
    $query->fieldCondition('tincan_instructor', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
    $query->fieldCondition('tincan_team', 'target_id', $all_agents, 'IN');
//need OR between fields conditions
//but then nested in the OR structure we need an AND for two columns of the multientity type reference field tincan_object
    $query->fieldCondition('tincan_object', 'target_id', $all_agents, 'IN');
    $query->fieldCondition('tincan_object', 'object_type', array('Agent', 'Group'), 'IN');
    $results = $query->$execute();

솔루션 : 위의 EntityFieldQuery에있는주의 사항

 $query->addTag('tincan_statement_get_agents');

이것은 쿼리에 태그를 지정하여 hook_query_TAG_alter ()의 구현을 허용합니다.

/**
 * Implements hook_query_TAG_alter()
 * alters the query for finding agents with or without the related_agents flag
 * used for Statement API Get processor EntityFieldQuery
 */
function tincan_lrs_query_tincan_statement_get_agents_alter(QueryAlterableInterface $query) {
  //need to or the search for all the fields (actor, object, authority, instructor, team)
  // the object_type of the object field needs to be Agent OR Group

  $conditions =& $query->conditions();
  // dsm($conditions);  //dsm() is your friend! comes with devel module
  $agent_grouping_condition = db_or(); 
  $object_parameters = array();
  $x = 0;
  foreach ($conditions as $key => $condition) {
    if (is_numeric($key) && isset($condition['field']) && is_scalar($condition['field'])) {
      if ( (strpos($condition['field'], 'tincan_object_object_type') !== FALSE  ||
          strpos($condition['field'], 'tincan_object_target_id') !== FALSE ) && $condition['operator'] == 'IN') {
  //u
            unset($conditions[$key]);
            $object_parameters[$x]['field'] = $condition['field'];
            $object_parameters[$x]['value'] = $condition['value'];
            $object_parameters[$x]['operator'] = $condition['operator'];
            $x += 1;
          }

       if(strpos($condition['field'], 'tincan_actor_target_id') !== FALSE ||
          strpos($condition['field'], 'tincan_instructor_target_id') !== FALSE ||
          strpos($condition['field'], 'tincan_team_target_id') !== FALSE ||
          strpos($condition['field'], 'tincan_authority_target_id') !== FALSE ) {
            unset($conditions[$key]);
            $agent_grouping_condition->condition($condition['field'], $condition['value'], $condition['operator']);

      } 
    }
  }

  // create new AND condition to nest in our OR condition set for the object parameters
  $object_condition = db_and();
  foreach($object_parameters as $key => $param) {
    $object_condition->condition($param['field'], $param['value'], $param['operator']);
  }

  $agent_grouping_condition->condition($object_condition);

  $query->condition($agent_grouping_condition);

  //By default EntityFieldQuery uses inner joins, change to left
  $tables =& $query->getTables();

  foreach($tables as $key => $table) {
    if (strpos($key, 'field_data_tincan_object') !== FALSE ||
        strpos($key, 'field_data_tincan_actor') !== FALSE ||
        strpos($key, 'field_data_tincan_authority') !== FALSE ||
        strpos($key, 'field_data_tincan_instructor') !== FALSE ||
        strpos($key, 'field_data_tincan_team') !== FALSE ) {
          if(!is_null($table['join type'])) {
            $tables[$key]['join type'] = 'LEFT';
          }
    }
  }

}

2

OP는 날짜가 null이거나 x보다 큰 엔티티를 쿼리하려고합니다. 언어가 정의되지 않은 노드 또는 사용자 언어를 쿼리하고 싶습니다. addTag()실제 OR 문을 추가하는 가장 좋은 솔루션이지만 제 경우에는 과잉입니다. 매우 간단한 OR은 다음을 사용하여 배열에서 언어 속성을 조회하여 수행 할 수 있습니다.

$query->propertyCondition('language', array($GLOBALS['language']->language, LANGUAGE_NONE), 'IN');
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.