VEYA EntityFieldQuery ile kullanma


26

Bugüne önce bunu gereğini yoktu, ama yapmak YA ile sorguları olabilir gibi görünmüyor EntityFieldQueryçünkü db_orseçme sorguları için kullanılır.

Bir örnek, değerin null olduğu veya bugünden sonraki bir tarih alanı olan tüm varlıklara verilebilir.

Bir şey mi kaçırıyorum yoksa bir numara mı var, yoksa bu desteklenmiyor mu?


Ayrıca bir sorguyu ikiye bölebilir, çalıştırabilir ve sonra sonuçları birleştirebilirsiniz.
Vadym Myrgorod

Sorguların veya veri miktarının uzaktan bile daha büyük olması durumunda, bunun performans üzerindeki etkisi oldukça korkunçtur.
Tommi Forsström

1
Bu eski ancak google sonuçlarımda oldukça yüksek - bunun için Drupal 8’de orConditionGroup’u kullanabileceğinizi belirtmelisiniz.
ognockocaten

Yanıtlar:


22

Bu sorunun bir çözümünü gördüm . Fikir, eski nesnenin iyi olduğu addTag()sorgulama ve uygulamada kullanmaktır .hook_query_TAG_alter()SelectQuery


Bunu doğru cevap olarak seçmeyi öneriyorum. Blog yazısı, EntityFieldQueries’e OR koşullu eklemek için bir yöntem sunar. Tek sorun, aslında EFQ'ların bütünüyle aynı olan ancak en azından işi yapan bu yöntemle SQL bağımlılığı yaratmanızdır. İyi bağlantı için @Michael.
Tommi Forsström

2
Bu bir topluluk cevabı olduğundan ve çoğu harici bir bağlantıdan oluştuğu için, kodun ya da en azından makalenin içeriğinin bir kısmının bu cevaba dahil edilmesi gerektiğini düşünüyorum. Çünkü bağlantılar ölür. Bu konu hakkında Meta StackExchange tartışması
D. Visser

Orijinal makale oldukça uzundur ve fikir "sorguda addTag () kullanın ve hook_query_TAG_alter ()" ifadesini uygulayın. Bundan sonra, soru bilinen konu olan "OR veya SelectQuery nesnesiyle nasıl kullanılır" olarak indirgenmiştir.
Michael

EFQ’yu bu senaryoda normal seçim sorgusuna dönüştürmenizi şiddetle tavsiye ederim. EFQ'ya bağlı kalmak ve ürettiği şeyle uğraşmak için etikete dayalı değişiklikleri kullanmak karşılaştırmalı olarak korkunç.
phils

12

EntityFieldQueryBazı yöntemleri alt sınıflandırabilir ve geçersiz kılabilirsiniz.

Bir sınıf nesnesine EntityFieldQuery(örneğin bir özellik koşulu) eklenen koşullar bir diziye eklenir.

  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;
  }

Sorgu oluşturulduğunda, bu dizi aşağıdakine benzer bir döngüde kullanılır (kod EntityFieldQuery :: propertyQuery () içinde bulunur ):

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

$select_queryçağrıdan döndürülen değeri içerir db_select().


5

Korkarım ki, OR'lar EntityFieldQuerysınıf tarafından doğal olarak desteklenmiyor .

Bunun bir yolu, sorguyla birlikte bir etiket eklemek ->addTag(), daha sonra hook_query_TAG_alter()bu etiketi içeren sorgular için sorgunun iç yapısını el ile değiştirmek için uygulamak olabilir.

Bunu yaparak mevcut koşullar arasında geçiş yapabilecek ve ORmantığınızı eklemek için gerekli değişiklikleri yapabileceksiniz . Yine de yapmanın güzel bir yolu değil; Burada bir örnek bulabilirsiniz .


5

Sorguları ikiye bölmeye ve birleştirmeye ya da onun gibi bir şeye gerek yok. Sadece sorguyu değiştirmelisin

Senaryoyu inceleyin: Makine isimlerinde 2 varlık tipim vardı: tincan deyimleri ve tincan_agents

Varlık üzerinde 5 varlık referans alanı

Bunlardan 4 tanesi normal varlık başvuru alanıdır ve 5'inci (tincan_object) çok varlıklı bir başvuru alanıdır, her başvuru alanı 'Ajan' tipi bir varlığa atıfta bulunur.

Tincan_object başvuru alanı, Acentelere ve Faaliyetlere başvurabilir (üçüncü bir varlık türü). Bir Ajanın, Ajan veya Grup olabilen bir özelliği object_type vardır.

Herhangi bir referans alanında, olası birkaç Ajandan birine referansta bulunan herhangi bir Bildirimi bulmak istiyorum. FieldConditions arasında bir OR işlecine ihtiyacımız var, ancak çok varlıklı tür başvuru alanının object_type değerini de kontrol etmemiz ve bunun iki olasılıktan biri olduğundan emin olmamız gerekiyor.

Aşağıdaki kod mümkün olan en basit ifadeyi temsil eder, çözümümüzde sorgunun birçok başka koşulu, alanı vb. Vardı, bu yüzden şartların sırasına göre sayılmaması gereken kod ya da bu alanların tümü sorgulanıyor olsa bile.

    $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();

Çözüm: Yukarıdaki EntityFieldQuery'deki uyarı

 $query->addTag('tincan_statement_get_agents');

Bu, sorguyu etiketleyerek hook_query_TAG_alter () işlevinin uygulanmasına izin verir

/**
 * 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 VEYA x'ten büyük olan varlıkları sorgulamak istiyor, dili tanımlanmış bir VEYA kullanıcının dili olmayan düğümler için sorgulamak istedim. addTag()Gerçek bir OR ifadesi eklemek için en iyi çözümdür, ancak benim durumumda fazla overkill olurdu. Çok basit OR'um, aşağıdakileri kullanarak bir dizideki dil özelliğini bakarak gerçekleştirilebilir:

$query->propertyCondition('language', array($GLOBALS['language']->language, LANGUAGE_NONE), 'IN');
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.