EntityFieldQuery के साथ OR का उपयोग करना


26

मैं आज से पहले यह करने के लिए की जरूरत थी कभी नहीं किया है, लेकिन जैसे आप कर सकते हैं या साथ प्रश्नों कर सकते हैं ऐसा प्रतीत नहीं होता EntityFieldQueryहै, क्योंकि db_orचयन प्रश्नों के लिए प्रयोग किया जाता है।

एक उदाहरण उन सभी संस्थाओं को मिलेगा जिनके पास एक दिनांक फ़ील्ड है जहां मान शून्य या आज के बाद है।

क्या मुझे कुछ या कुछ ट्रिक याद आ रही है या यह बस समर्थित नहीं है?


आप एक क्वेरी को दो में विभाजित कर सकते हैं, उन्हें चला सकते हैं और फिर परिणाम जोड़ सकते हैं।
वडियम मायरोडर

यदि प्रश्नों या डेटा की मात्रा को दूरस्थ रूप से बड़ा किया जाए तो इसका प्रदर्शन प्रभाव बहुत भयानक होता है।
टॉमी फोर्सस्ट्रॉम 19

1
यह मेरे Google परिणामों में पुराना लेकिन उच्च है - यह ध्यान दिया जाना चाहिए कि आप Drupal 8. में इसके लिए orConditionGroup का उपयोग कर सकते हैं
ognognocaten

जवाबों:


22

मैंने इस समस्या का हल देखा है । यह विचार addTag()क्वेरी और उपयोग में है hook_query_TAG_alter(), जहां आपके पास अच्छी पुरानी SelectQueryवस्तु है।


मैं इसे सही उत्तर के रूप में चुनने का प्रस्ताव देता हूं। ब्लॉग पोस्ट EntityFieldQueries के लिए OR सशर्तता जोड़ने के लिए एक विधि प्रदान करता है। एकमात्र समस्या यह है कि आप वास्तव में उस पद्धति के साथ SQL निर्भरता का निर्माण करते हैं, जो कि EFQs के पूरे बिंदु के खिलाफ है, लेकिन कम से कम काम हो जाता है। अच्छे लिंक @ मिचेल के लिए धन्यवाद।
टॉमी फोर्सस्ट्रॉम 19

2
चूंकि यह एक सामुदायिक उत्तर है, और इसमें से अधिकांश में एक बाहरी लिंक शामिल है, मुझे लगता है कि कोड, या कम से कम लेख की कुछ सामग्री इस उत्तर में शामिल होनी चाहिए। क्योंकि लिंक मर जाते हैं। इस विषय पर मेटा स्टैकएक्सचेंज चर्चा
डी।

मूल लेख लंबा है और इस विचार को संक्षेप में "उपयोग AddTag () क्वेरी में और हुक_क्वेरी_TAG_alter ()" के रूप में संक्षेपित किया जा सकता है। उसके बाद यह प्रश्न "विषय वस्तु के रूप में उपयोग कैसे करें या SelectQuery वस्तु के साथ" को घटा दिया गया है।
माइकल

मैं इस परिदृश्य में 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

आप मुझे डर नहीं सकते, ओआरएस मूल रूप से EntityFieldQueryवर्ग द्वारा समर्थित नहीं हैं ।

एक तरह से इसके साथ क्वेरी में एक टैग जोड़ने का दौर हो सकता है ->addTag(), फिर क्वेरी hook_query_TAG_alter()के आंतरिक ढांचे को मैन्युअल रूप से उस टैग वाले प्रश्नों के लिए बदलने के लिए लागू करें।

ऐसा करने से आप मौजूदा स्थितियों के माध्यम से लूप कर पाएंगे और अपने ORतर्क को जोड़ने के लिए आवश्यक परिवर्तन कर पाएंगे । हालांकि यह करने के लिए एक सुंदर तरीका नहीं है; आप यहां एक उदाहरण पा सकते हैं ।


5

प्रश्नों को 2 में विभाजित करने और विलय या ऐसा कुछ भी करने की आवश्यकता नहीं है। बस क्वेरी को बदलने की जरूरत है

परिदृश्य पर विचार करें: मेरे पास मशीन के नाम के साथ 2 इकाई प्रकार थे: टिनकान स्टेटमेंट्स, और टिंचन_एगेंट्स

इकाई पर 5 इकाई संदर्भ फ़ील्ड

उनमें से 4 नियमित इकाई संदर्भ क्षेत्र हैं और 5 वां (tincan_object) एक बहु-इकाई-प्रकार संदर्भ क्षेत्र है, प्रत्येक संदर्भ फ़ील्ड प्रकार 'एजेंट' की संस्थाओं का संदर्भ देता है।

Tincan_object संदर्भ क्षेत्र एजेंटों और गतिविधियों (एक तीसरी इकाई प्रकार) को संदर्भित कर सकता है। एक एजेंट के पास एक संपत्ति 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');

यह क्वेरी को टैग करता है, हुक_क्वेरी_एजीए_एल्टर () के कार्यान्वयन की अनुमति देता है

/**
 * 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

ओपी डेट के साथ संस्थाओं के लिए क्वेरी करना चाहता है null या x से बड़ा, मैं नोड्स के लिए क्वेरी करना चाहता था जिसमें कोई भाषा परिभाषित या उपयोगकर्ता की भाषा नहीं है। addTag()एक वास्तविक OR कथन जोड़ने के लिए सबसे अच्छा समाधान है, लेकिन मेरे मामले में ओवरकिल होगा। मेरे बहुत ही सरल या उपयोग में एक सरणी में भाषा की संपत्ति को देखकर पूरा किया जा सकता है:

$query->propertyCondition('language', array($GLOBALS['language']->language, LANGUAGE_NONE), 'IN');
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.