14. Doctrine Query Language

DQL stands for Doctrine Query Language and is an Object Query Language derivative that is very similar to the Hibernate Query Language (HQL) or the Java Persistence Query Language (JPQL).

DQL は Doctrine Query Language の略で、HibernateQuery Language (HQL) または Java Persistence Query Language (JPQL) に非常によく似た ObjectQuery Language の派生物です。

In essence, DQL provides powerful querying capabilities over your object model. Imagine all your objects lying around in some storage (like an object database). When writing DQL queries, think about querying that storage to pick a certain subset of your objects.

本質的に、DQL はオブジェクト モデルに対する強力なクエリ機能を提供します。すべてのオブジェクトが何らかのストレージ (オブジェクト データベースなど) にあると想像してください。 DQL クエリを作成するときは、そのストレージにクエリを実行してオブジェクトの特定のサブセットを選択することを検討してください。

Note

ノート

A common mistake for beginners is to mistake DQL for being just some form of SQL and therefore trying to use table names and column names or join arbitrary tables together in a query. You need to think about DQL as a query language for your object model, not for your relational schema.

初心者によくある間違いは、DQL を単なる SQL の形式であると誤解して、テーブル名と列名を使用したり、クエリで任意のテーブルを結合しようとしたりすることです。 DQL は、リレーショナル スキーマではなく、オブジェクト モデルのクエリ言語として考える必要があります。

DQL is case in-sensitive, except for namespace, class and field names, which are case sensitive.

DQL では、大文字と小文字が区別される名前空間、クラス、およびフィールド名を除いて、大文字と小文字が区別されません。

14.1. Types of DQL queries

DQL as a query language has SELECT, UPDATE and DELETE constructs that map to their corresponding SQL statement types. INSERT statements are not allowed in DQL, because entities and their relations have to be introduced into the persistence context through EntityManager#persist() to ensure consistency of your object model.

クエリ言語としての DQL には、対応する SQL ステートメントの型に対応する SELECT、UPDATE、および DELETE 構造があります。 DQL では INSERT ステートメントは使用できません。これは、オブジェクト モデルの一貫性を確保するために、EntityManager#persist() を介してエンティティとその関係を永続化コンテキストに導入する必要があるためです。

DQL SELECT statements are a very powerful way of retrieving parts of your domain model that are not accessible via associations. Additionally they allow you to retrieve entities and their associations in one single SQL select statement which can make a huge difference in performance compared to using several queries.

DQL SELECT ステートメントは、関連付けを介してアクセスできないドメイン モデルの部分を取得するための非常に強力な方法です。さらに、単一の SQL 選択ステートメントでエンティティとその関連付けを取得できるため、複数のクエリを使用する場合と比べてパフォーマンスが大きく異なります。

DQL UPDATE and DELETE statements offer a way to execute bulk changes on the entities of your domain model. This is often necessary when you cannot load all the affected entities of a bulk update into memory.

DQL UPDATE および DELETE ステートメントは、ドメイン モデルのエンティティに対して一括変更を実行する方法を提供します。これは、一括更新の影響を受けるすべてのエンティティをメモリにロードできない場合に必要になることがよくあります。

14.2. SELECT queries

14.2.1. DQL SELECT clause

Here is an example that selects all users with an age > 20:

以下は、年齢が 20 歳を超えるすべてのユーザーを選択する例です。

<?php
$query = $em->createQuery('SELECT u FROM MyProject\Model\User u WHERE u.age > 20');
$users = $query->getResult();

Lets examine the query:

クエリを調べてみましょう。

  • u is a so called identification variable or alias that refers to the MyProject\Model\User class. By placing this alias in the SELECT clause we specify that we want all instances of the User class that are matched by this query to appear in the query result.

    u は、MyProject\Model\User クラスを参照する、いわゆる識別変数またはエイリアスです。このエイリアスを SELECT 句に配置することで、このクエリに一致する User クラスのすべてのインスタンスがクエリ結果に表示されるように指定します。

  • The FROM keyword is always followed by a fully-qualified class name which in turn is followed by an identification variable or alias for that class name. This class designates a root of our query from which we can navigate further via joins (explained later) and path expressions.

    FROM キーワードの後に​​は常に完全修飾クラス名が続き、その後にそのクラス名の識別変数 oralias が続きます。このクラスは、結合 (後述) とパス式を介してさらにナビゲートできるクエリのルートを指定します。

  • The expression u.age in the WHERE clause is a path expression. Path expressions in DQL are easily identified by the use of the ‘.’ operator that is used for constructing paths. The path expression u.age refers to the age field on the User class.

    WHERE 句の式 u.age はパス式です。 DQL のパス式は、パスの構築に使用される「.」演算子を使用することで簡単に識別できます。パス式 u.age は、Userclass の age フィールドを参照します。

The result of this query would be a list of User objects where all users are older than 20.

このクエリの結果は、すべてのユーザーが 20 歳以上のユーザー オブジェクトのリストになります。

14.2.2. Result format

The composition of the expressions in the SELECT clause also influences the nature of the query result. There are three cases:

SELECT 句の式の構成も、クエリ結果の性質に影響します。次の 3 つのケースがあります。

All objects

すべてのオブジェクト

SELECT u, p, n FROM Users u...

In this case, the result will be an array of User objects because of the FROM clause, with children p and n hydrated because of their inclusion in the SELECT clause.

この場合、FROM 句のために結果は User オブジェクトの配列になり、子 p と n は SELECT 句に含まれているため水和されます。

All scalars

すべてのスカラー

SELECT u.name, u.address FROM Users u...

In this case, the result will be an array of arrays. In the example above, each element of the result array would be an array of the scalar name and address values.

この場合、結果は配列の配列になります。上記の例では、結果配列の各要素は、スカラー名とアドレス値の配列になります。

You can select scalars from any entity in the query.

クエリ内の任意のエンティティからスカラーを選択できます。

Mixed

混合

SELECT u, p.quantity FROM Users u...

Here, the result will again be an array of arrays, with each element being an array made up of a User object and the scalar value p.quantity.

ここでも、結果は配列の配列になり、各要素は User オブジェクトとスカラー値 p.quantity で構成される配列になります。

Multiple FROM clauses are allowed, which would cause the result array elements to cycle through the classes included in the multiple FROM clauses.

複数の FROM 句を使用できます。これにより、resultarray 要素が複数の FROM 句に含まれるクラスを循環します。

Note

ノート

You cannot select other entities unless you also select the root of the selection (which is the first entity in FROM).

選択のルート (FROM の最初のエンティティ) も選択しない限り、他のエンティティを選択することはできません。

For example, SELECT p,n FROM Users u... would be wrong because u is not part of the SELECT

たとえば、SELECT p,n FROM Users u... は間違っています。なぜなら、u は SELECT の一部ではないからです。

Doctrine throws an exception if you violate this constraint.

この制約に違反すると、Doctrine は例外をスローします。

14.2.3. Joins

A SELECT query can contain joins. There are 2 types of JOINs: “Regular” Joins and “Fetch” Joins.

SELECT クエリには結合を含めることができます。 JOIN には、「通常の」結合と「フェッチ」結合の 2 種類があります。

Regular Joins: Used to limit the results and/or compute aggregate values.

通常の結合: 結果を制限したり、集計値を計算したりするために使用されます。

Fetch Joins: In addition to the uses of regular joins: Used to fetch related entities and include them in the hydrated result of a query.

フェッチ結合: 通常の結合の使用に加えて: 関連するエンティティをフェッチし、それらをクエリの水和結果に含めるために使用されます。

There is no special DQL keyword that distinguishes a regular join from a fetch join. A join (be it an inner or outer join) becomes a “fetch join” as soon as fields of the joined entity appear in the SELECT part of the DQL query outside of an aggregate function. Otherwise its a “regular join”.

通常の結合とフェッチ結合を区別する特別な DQL キーワードはありません。結合 (内部結合または外部結合) は、結合されたエンティティのフィールドが集計関数の外側の DQL クエリの SELECT 部分に現れるとすぐに「フェッチ結合」になります。それ以外の場合は「通常の結合」です。

Example:

例:

Regular join of the address:

アドレスの通常の結合:

<?php
$query = $em->createQuery("SELECT u FROM User u JOIN u.address a WHERE a.city = 'Berlin'");
$users = $query->getResult();

Fetch join of the address:

アドレスの結合をフェッチします。

<?php
$query = $em->createQuery("SELECT u, a FROM User u JOIN u.address a WHERE a.city = 'Berlin'");
$users = $query->getResult();

When Doctrine hydrates a query with fetch-join it returns the class in the FROM clause on the root level of the result array. In the previous example an array of User instances is returned and the address of each user is fetched and hydrated into the User#address variable. If you access the address Doctrine does not need to lazy load the association with another query.

Doctrine が fetch-join でクエリをハイドレートすると、結果配列のルートレベルの FROM 句でクラスが返されます。前の例では、User インスタンスの配列が返され、各ユーザーのアドレスが取得され、User#address 変数に格納されます。アドレスにアクセスする場合、Doctrine は別のクエリとの関連付けを遅延ロードする必要はありません。

Note

ノート

Doctrine allows you to walk all the associations between all the objects in your domain model. Objects that were not already loaded from the database are replaced with lazy-loading proxy instances. Non-loaded Collections are also replaced by lazy-loading instances that fetch all the contained objects upon first access. However relying on the lazy-loading mechanism leads to many small queries executed against the database, which can significantly affect the performance of your application. Fetch Joins are the solution to hydrate most or all of the entities that you need in a single SELECT query.

Doctrine を使用すると、ドメイン モデル内のすべてのオブジェクト間のすべての関連付けをたどることができます。データベースからまだロードされていないオブジェクトは、遅延ロード プロキシ インスタンスに置き換えられます。ロードされていないコレクションも、最初のアクセス時に含まれているすべてのオブジェクトをフェッチする遅延ロード インスタンスに置き換えられます。ただし、遅延ロード メカニズムに依存すると、データベースに対して多くの小さなクエリが実行され、アプリケーションのパフォーマンスに大きな影響を与える可能性があります。フェッチ結合は、単一の SELECT クエリで必要なエンティティのほとんどまたはすべてを水和するソリューションです。

14.2.4. Named and Positional Parameters

DQL supports both named and positional parameters, however in contrast to many SQL dialects positional parameters are specified with numbers, for example “?1”, “?2” and so on. Named parameters are specified with “:name1”, “:name2” and so on.

DQL は名前付きパラメーターと位置パラメーターの両方をサポートしますが、多くの SQL ダイアレクトとは対照的に、位置パラメーターは「?1」、「?2」などの数字で指定されます。名前付きパラメータは、「:name1」、「:name2」などで指定されます。

When referencing the parameters in Query#setParameter($param, $value) both named and positional parameters are used without their prefixes.

Query#setParameter($param, $value) でパラメーターを参照する場合、名前付きパラメーターと位置パラメーターの両方がプレフィックスなしで使用されます。

14.2.5. DQL SELECT Examples

This section contains a large set of DQL queries and some explanations of what is happening. The actual result also depends on the hydration mode.

このセクションには、多数の DQL クエリのセットと、何が起こっているのかについての説明が含まれています。実際の結果は、水分補給モードにも依存します。

Hydrate all User entities:

すべてのユーザー エンティティをハイドレートします。

<?php
$query = $em->createQuery('SELECT u FROM MyProject\Model\User u');
$users = $query->getResult(); // array of User objects

Retrieve the IDs of all CmsUsers:

すべての CmsUsers の ID を取得します。

<?php
$query = $em->createQuery('SELECT u.id FROM CmsUser u');
$ids = $query->getResult(); // array of CmsUser ids

Retrieve the IDs of all users that have written an article:

記事を書いたすべてのユーザーの ID を取得します。

<?php
$query = $em->createQuery('SELECT DISTINCT u.id FROM CmsArticle a JOIN a.user u');
$ids = $query->getResult(); // array of CmsUser ids

Retrieve all articles and sort them by the name of the articles users instance:

すべての記事を取得し、articleusers インスタンスの名前で並べ替えます。

<?php
$query = $em->createQuery('SELECT a FROM CmsArticle a JOIN a.user u ORDER BY u.name ASC');
$articles = $query->getResult(); // array of CmsArticle objects

Retrieve the Username and Name of a CmsUser:

CmsUser のユーザー名と名前を取得します。

<?php
$query = $em->createQuery('SELECT u.username, u.name FROM CmsUser u');
$users = $query->getResult(); // array of CmsUser username and name values
echo $users[0]['username'];

Retrieve a ForumUser and its single associated entity:

ForumUser とそれに関連付けられた単一のエンティティを取得します。

<?php
$query = $em->createQuery('SELECT u, a FROM ForumUser u JOIN u.avatar a');
$users = $query->getResult(); // array of ForumUser objects with the avatar association loaded
echo get_class($users[0]->getAvatar());

Retrieve a CmsUser and fetch join all the phonenumbers it has:

CmsUser を取得し、そこにあるすべての電話番号を取得して結合します。

<?php
$query = $em->createQuery('SELECT u, p FROM CmsUser u JOIN u.phonenumbers p');
$users = $query->getResult(); // array of CmsUser objects with the phonenumbers association loaded
$phonenumbers = $users[0]->getPhonenumbers();

Hydrate a result in Ascending:

昇順で結果を水和する:

<?php
$query = $em->createQuery('SELECT u FROM ForumUser u ORDER BY u.id ASC');
$users = $query->getResult(); // array of ForumUser objects

Or in Descending Order:

または降順で:

<?php
$query = $em->createQuery('SELECT u FROM ForumUser u ORDER BY u.id DESC');
$users = $query->getResult(); // array of ForumUser objects

Using Aggregate Functions:

集計関数の使用:

<?php
$query = $em->createQuery('SELECT COUNT(u.id) FROM Entities\User u');
$count = $query->getSingleScalarResult();

$query = $em->createQuery('SELECT u, count(g.id) FROM Entities\User u JOIN u.groups g GROUP BY u.id');
$result = $query->getResult();

With WHERE Clause and Positional Parameter:

WHERE 句と定位置パラメーターを使用:

<?php
$query = $em->createQuery('SELECT u FROM ForumUser u WHERE u.id = ?1');
$query->setParameter(1, 321);
$users = $query->getResult(); // array of ForumUser objects

With WHERE Clause and Named Parameter:

WHERE 句と名前付きパラメーターを使用:

<?php
$query = $em->createQuery('SELECT u FROM ForumUser u WHERE u.username = :name');
$query->setParameter('name', 'Bob');
$users = $query->getResult(); // array of ForumUser objects

With Nested Conditions in WHERE Clause:

WHERE 句にネストされた条件がある場合:

<?php
$query = $em->createQuery('SELECT u FROM ForumUser u WHERE (u.username = :name OR u.username = :name2) AND u.id = :id');
$query->setParameters([
    'name' => 'Bob',
    'name2' => 'Alice',
    'id' => 321,
]);
$users = $query->getResult(); // array of ForumUser objects

With COUNT DISTINCT:

COUNT DISTINCT の場合:

<?php
$query = $em->createQuery('SELECT COUNT(DISTINCT u.name) FROM CmsUser');
$users = $query->getResult(); // array of ForumUser objects

With Arithmetic Expression in WHERE clause:

WHERE 句に算術式を使用する場合:

<?php
$query = $em->createQuery('SELECT u FROM CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000');
$users = $query->getResult(); // array of ForumUser objects

Retrieve user entities with Arithmetic Expression in ORDER clause, using the HIDDEN keyword:

HIDDEN キーワードを使用して、ORDER 句で算術式を使用してユーザー エンティティを取得します。

<?php
$query = $em->createQuery('SELECT u, u.posts_count + u.likes_count AS HIDDEN score FROM CmsUser u ORDER BY score');
$users = $query->getResult(); // array of User objects

Using a LEFT JOIN to hydrate all user-ids and optionally associated article-ids:

LEFT JOIN を使用して、すべてのユーザー ID と、オプションで関連付けられた記事 ID をハイドレートします。

<?php
$query = $em->createQuery('SELECT u.id, a.id as article_id FROM CmsUser u LEFT JOIN u.articles a');
$results = $query->getResult(); // array of user ids and every article_id for each user

Restricting a JOIN clause by additional conditions specified by WITH:

WITH で指定された追加条件による JOIN 句の制限:

<?php
$query = $em->createQuery("SELECT u FROM CmsUser u LEFT JOIN u.articles a WITH a.topic LIKE :foo");
$query->setParameter('foo', '%foo%');
$users = $query->getResult();

Using several Fetch JOINs:

複数の Fetch JOIN を使用する:

<?php
$query = $em->createQuery('SELECT u, a, p, c FROM CmsUser u JOIN u.articles a JOIN u.phonenumbers p JOIN a.comments c');
$users = $query->getResult();

BETWEEN in WHERE clause:

BETWEEN WHERE 句:

<?php
$query = $em->createQuery('SELECT u.name FROM CmsUser u WHERE u.id BETWEEN ?1 AND ?2');
$query->setParameter(1, 123);
$query->setParameter(2, 321);
$usernames = $query->getResult();

DQL Functions in WHERE clause:

WHERE 句の DQL 関数:

<?php
$query = $em->createQuery("SELECT u.name FROM CmsUser u WHERE TRIM(u.name) = 'someone'");
$usernames = $query->getResult();

IN() Expression:

IN() 式:

<?php
$query = $em->createQuery('SELECT u.name FROM CmsUser u WHERE u.id IN(46)');
$usernames = $query->getResult();

$query = $em->createQuery('SELECT u FROM CmsUser u WHERE u.id IN (1, 2)');
$users = $query->getResult();

$query = $em->createQuery('SELECT u FROM CmsUser u WHERE u.id NOT IN (1)');
$users = $query->getResult();

CONCAT() DQL Function:

CONCAT() DQL 関数:

<?php
$query = $em->createQuery("SELECT u.id FROM CmsUser u WHERE CONCAT(u.name, 's') = ?1");
$query->setParameter(1, 'Jess');
$ids = $query->getResult();

$query = $em->createQuery('SELECT CONCAT(u.id, u.name) FROM CmsUser u WHERE u.id = ?1');
$query->setParameter(1, 321);
$idUsernames = $query->getResult();

EXISTS in WHERE clause with correlated Subquery

EXISTS in WHERE 句と相関サブクエリ

<?php
$query = $em->createQuery('SELECT u.id FROM CmsUser u WHERE EXISTS (SELECT p.phonenumber FROM CmsPhonenumber p WHERE p.user = u.id)');
$ids = $query->getResult();

Get all users who are members of $group.

$group のメンバーであるすべてのユーザーを取得します。

<?php
$query = $em->createQuery('SELECT u.id FROM CmsUser u WHERE :groupId MEMBER OF u.groups');
$query->setParameter('groupId', $group);
$ids = $query->getResult();

Get all users that have more than 1 phonenumber

複数の電話番号を持つすべてのユーザーを取得する

<?php
$query = $em->createQuery('SELECT u FROM CmsUser u WHERE SIZE(u.phonenumbers) > 1');
$users = $query->getResult();

Get all users that have no phonenumber

電話番号を持たないすべてのユーザーを取得する

<?php
$query = $em->createQuery('SELECT u FROM CmsUser u WHERE u.phonenumbers IS EMPTY');
$users = $query->getResult();

Get all instances of a specific type, for use with inheritance hierarchies:

継承階層で使用するために、特定の型のすべてのインスタンスを取得します。

<?php
$query = $em->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF Doctrine\Tests\Models\Company\CompanyEmployee');
$query = $em->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u INSTANCE OF ?1');
$query = $em->createQuery('SELECT u FROM Doctrine\Tests\Models\Company\CompanyPerson u WHERE u NOT INSTANCE OF ?1');

Get all users visible on a given website that have chosen certain gender:

特定の性別を選択した特定の Web サイトに表示されるすべてのユーザーを取得します。

<?php
$query = $em->createQuery('SELECT u FROM User u WHERE u.gender IN (SELECT IDENTITY(agl.gender) FROM Site s JOIN s.activeGenderList agl WHERE s.id = ?1)');

The IDENTITY() DQL function also works for composite primary keys

IDENTITY() DQL 関数は複合主キーにも機能します

<?php
$query = $em->createQuery("SELECT IDENTITY(c.location, 'latitude') AS latitude, IDENTITY(c.location, 'longitude') AS longitude FROM Checkpoint c WHERE c.user = ?1");

Joins between entities without associations are available, where you can generate an arbitrary join with the following syntax:

関連付けのないエンティティ間の結合が利用可能で、次の構文で任意の結合を生成できます。

<?php
$query = $em->createQuery('SELECT u FROM User u JOIN Banlist b WITH u.email = b.email');

With an arbitrary join the result differs from the joins using a mapped property. The result of an arbitrary join is an one dimensional array with a mix of the entity from the SELECT and the joined entity fitting to the filtering of the query. In case of the example with User and Banlist, it can look like this:

任意結合の結果は、マップされたプロパティを使用した結合とは異なります。任意結合の結果は、SELECT からのエンティティとクエリのフィルタリングに適合する結合エンティティが混在する 1 次元配列です。 Userand Banlist を使用した例の場合、次のようになります。

  • User

    ユーザー

  • Banlist

    禁止リスト

  • Banlist

    禁止リスト

  • User

    ユーザー

  • Banlist

    禁止リスト

  • User

    ユーザー

  • Banlist

    禁止リスト

  • Banlist

    禁止リスト

  • Banlist

    禁止リスト

In this form of join, the Banlist entities found by the filtering in the WITH part are not fetched by an accessor method on User, but are already part of the result. In case the accessor method for Banlists is invoked on a User instance, it loads all the related Banlist objects corresponding to this User. This change of behaviour needs to be considered when the DQL is switched to an arbitrary join.

この形式の結合では、WITH 部分でのフィルタリングによって検出された Banlist エンティティは、User のアクセサ メソッドによってフェッチされませんが、既に結果の一部になっています。 Banlists のアクセサ メソッドが User インスタンスで呼び出された場合、この User に対応するすべての関連 Banlist オブジェクトがロードされます。この動作の変更は、DQL が任意結合に切り替えられたときに考慮する必要があります。

Note

ノート

The differences between WHERE, WITH and HAVING clauses may be confusing.

WHERE、WITH、および HAVING 句の違いは、混乱を招く可能性があります。

  • WHERE is applied to the results of an entire query

    WHERE はクエリ全体の結果に適用されます

  • WITH is applied to a join as an additional condition. For arbitrary joins (SELECT f, b FROM Foo f, Bar b WITH f.id = b.id) the WITH is required, even if it is 1 = 1

    WITH は、追加条件として結合に適用されます。任意の結合 (SELECT f, b FROM Foo f, Bar b WITH f.id = b.id) の場合、1 = 1 であっても WITH が必要です。

  • HAVING is applied to the results of a query after aggregation (GROUP BY)

    HAVING は、集計 (GROUP BY) 後にクエリの結果に適用されます。

14.2.5.1. Partial Object Syntax

By default when you run a DQL query in Doctrine and select only a subset of the fields for a given entity, you do not receive objects back. Instead, you receive only arrays as a flat rectangular result set, similar to how you would if you were just using SQL directly and joining some data.

デフォルトでは、Doctrine で DQL クエリを実行し、特定のエンティティのフィールドのサブセットのみを選択すると、オブジェクトが返されません。代わりに、SQL を直接使用して一部のデータを結合する場合と同様に、配列のみを平らな長方形の結果セットとして受け取ります。

If you want to select partial objects you can use the partial DQL keyword:

部分的なオブジェクトを選択したい場合は、partialDQL キーワードを使用できます。

<?php
$query = $em->createQuery('SELECT partial u.{id, username} FROM CmsUser u');
$users = $query->getResult(); // array of partially loaded CmsUser objects

You use the partial syntax when joining as well:

結合するときも部分構文を使用します。

<?php
$query = $em->createQuery('SELECT partial u.{id, username}, partial a.{id, name} FROM CmsUser u JOIN u.articles a');
$users = $query->getResult(); // array of partially loaded CmsUser objects

14.2.5.2. “NEW” Operator Syntax

Using the NEW operator you can construct Data Transfer Objects (DTOs) directly from DQL queries.

NEW 演算子を使用すると、DQL クエリから直接データ転送オブジェクト (DTO) を構築できます。

  • When using SELECT NEW you don’t need to specify a mapped entity.

    SELECT NEW を使用する場合、マップされたエンティティを指定する必要はありません。

  • You can specify any PHP class, it only requires that the constructor of this class matches the NEW statement.

    任意の PHP クラスを指定できます。必要なのは、このクラスのコンストラクターが NEW ステートメントと一致することだけです。

  • This approach involves determining exactly which columns you really need, and instantiating a data-transfer object that contains a constructor with those arguments.

    このアプローチには、本当に必要な列を正確に決定し、それらの引数を持つコンストラクターを含むデータ転送オブジェクトをインスタンス化することが含まれます。

If you want to select data-transfer objects you should create a class:

データ転送オブジェクトを選択したい場合は、クラスを作成する必要があります:

<?php
class CustomerDTO
{
    public function __construct($name, $email, $city, $value = null)
    {
        // Bind values to the object properties.
    }
}

And then use the NEW DQL keyword :

次に NEW DQL キーワードを使用します。

<?php
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city) FROM Customer c JOIN c.email e JOIN c.address a');
$users = $query->getResult(); // array of CustomerDTO
<?php
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city, SUM(o.value)) FROM Customer c JOIN c.email e JOIN c.address a JOIN c.orders o GROUP BY c');
$users = $query->getResult(); // array of CustomerDTO

Note that you can only pass scalar expressions to the constructor.

コンストラクターにはスカラー式のみを渡すことができることに注意してください。

14.2.6. Using INDEX BY

The INDEX BY construct is nothing that directly translates into SQL but that affects object and array hydration. After each FROM and JOIN clause you specify by which field this class should be indexed in the result. By default a result is incremented by numerical keys starting with 0. However with INDEX BY you can specify any other column to be the key of your result, it really only makes sense with primary or unique fields though:

INDEX BY コンストラクトは、SQL に直接変換されるものではありませんが、オブジェクトと配列のハイドレーションに影響を与えます。各 FROM 句と JOIN 句の後に、結果でこのクラスのインデックスを作成するフィールドを指定します。デフォルトでは、結果は 0 から始まる数値キーによってインクリメントされます。ただし、INDEX BY を使用すると、他の列を結果のキーとして指定できますが、実際にはプライマリまたは一意のフィールドでのみ意味があります。

SELECT u.id, u.status, upper(u.name) nameUpper FROM User u INDEX BY u.id
JOIN u.phonenumbers p INDEX BY p.phonenumber

Returns an array of the following kind, indexed by both user-id then phonenumber-id:

user-id と phonenumber-id の両方でインデックス付けされた、次の種類の配列を返します。

array
  0 =>
    array
      1 =>
        object(stdClass)[299]
          public '__CLASS__' => string 'Doctrine\Tests\Models\CMS\CmsUser' (length=33)
          public 'id' => int 1
          ..
      'nameUpper' => string 'ROMANB' (length=6)
  1 =>
    array
      2 =>
        object(stdClass)[298]
          public '__CLASS__' => string 'Doctrine\Tests\Models\CMS\CmsUser' (length=33)
          public 'id' => int 2
          ...
      'nameUpper' => string 'JWAGE' (length=5)

You can also index by a to-one association, which will use the id of the associated entity (the join column) as the key in the result set:

また、結果セットのキーとして関連付けられたエンティティ (結合列) の ID を使用する対 1 関連付けによってインデックスを作成することもできます。

SELECT p, u FROM Participant INDEX BY p.user JOIN p.user u WHERE p.event = 3

14.3. UPDATE queries

DQL not only allows to select your Entities using field names, you can also execute bulk updates on a set of entities using an DQL-UPDATE query. The Syntax of an UPDATE query works as expected, as the following example shows:

DQL では、フィールド名を使用してエンティティを選択できるだけでなく、DQL-UPDATE クエリを使用して一連のエンティティに対して一括更新を実行することもできます。次の例に示すように、UPDATE クエリの構文は期待どおりに機能します。

UPDATE MyProject\Model\User u SET u.password = 'new' WHERE u.id IN (1, 2, 3)

References to related entities are only possible in the WHERE clause and using sub-selects.

関連するエンティティへの参照は、WHERE 句と副選択の使用でのみ可能です。

Warning

警告

DQL UPDATE statements are ported directly into a Database UPDATE statement and therefore bypass any locking scheme, events and do not increment the version column. Entities that are already loaded into the persistence context will NOT be synced with the updated database state. It is recommended to call EntityManager#clear() and retrieve new instances of any affected entity.

DQL UPDATE ステートメントはデータベース UPDATE ステートメントに直接移植されるため、ロック スキームやイベントをバイパスし、バージョン カラムをインクリメントしません。永続化コンテキストに既にロードされているエンティティは、更新されたデータベースの状態と同期されません。 EntityManager#clear() を呼び出して、影響を受けるエンティティの新しいインスタンスを取得することをお勧めします。

14.4. DELETE queries

DELETE queries can also be specified using DQL and their syntax is as simple as the UPDATE syntax:

DELETE クエリは DQL を使用して指定することもでき、その構文は UPDATE 構文と同じくらい簡単です。

DELETE MyProject\Model\User u WHERE u.id = 4

The same restrictions apply for the reference of related entities.

関連エンティティの参照にも同じ制限が適用されます。

Warning

警告

DQL DELETE statements are ported directly into an SQL DELETE statement. Therefore, some limitations apply:

DQL DELETE ステートメントは、SQL DELETE ステートメントに直接移植されます。したがって、いくつかの制限が適用されます。

  • Lifecycle events for the affected entities are not executed.

    影響を受けるエンティティのライフサイクル イベントは実行されません。

  • A cascading remove operation (as indicated e. g. by cascade: ['remove'] or cascade: ['all'] in the mapping configuration) is not being performed for associated entities. You can rely on database level cascade operations by configuring each join column with the onDelete option.

    カスケード削除操作 (たとえば、マッピング構成で cascade: ['remove'] または cascade: ['all'] で示される) が、関連付けられたエンティティに対して実行されていません。 onDelete オプションを使用して各結合列を構成することにより、データベース レベルのカスケード操作に依存できます。

  • Checks for the version column are bypassed if they are not explicitly added to the WHERE clause of the query.

    バージョン列のチェックは、クエリの WHERE 句に明示的に追加されていない場合、バイパスされます。

When you rely on one of these features, one option is to use the EntityManager#remove($entity) method. This, however, is costly performance-wise: It means collections and related entities are fetched into memory (even if they are marked as lazy). Pulling object graphs into memory on cascade can cause considerable performance overhead, especially when the cascaded collections are large. Make sure to weigh the benefits and downsides.

これらの機能のいずれかに依存する場合、1 つのオプションは、EntityManager#remove($entity) メソッドを使用することです。ただし、これはパフォーマンス面でコストがかかります。つまり、コレクションと関連するエンティティがメモリにフェッチされます (遅延としてマークされている場合でも)。カスケードでオブジェクト グラフをメモリにプルすると、特にカスケード コレクションが大きい場合に、かなりのパフォーマンス オーバーヘッドが発生する可能性があります。メリットとデメリットをよく比較検討してください。

14.5. Comments in queries

We can use comments with the SQL syntax of comments.

コメントの SQL 構文でコメントを使用できます。

SELECT u FROM MyProject\Model\User u
-- my comment
WHERE u.age > 20 -- comment at the end of a line

14.6. Functions, Operators, Aggregates

It is possible to wrap both fields and identification values into aggregation and DQL functions. Numerical fields can be part of computations using mathematical operations.

フィールドと識別値の両方を集計関数と DQL 関数にラップすることができます。数値フィールドは、数学演算を使用した計算の一部にすることができます。

14.6.1. DQL Functions

The following functions are supported in SELECT, WHERE and HAVING clauses:

次の関数は、SELECT、WHERE、および HAVING 句でサポートされています。

  • IDENTITY(single_association_path_expression [, fieldMapping]) - Retrieve the foreign key column of association of the owning side

    IDENTITY(single_association_path_expression [, fieldMapping]) ・所有側アソシエーションの外部キー列を取得

  • ABS(arithmetic_expression)

    ABS(算術式)

  • CONCAT(str1, str2)

    CONCAT(str1, str2)

  • CURRENT_DATE() - Return the current date

    CURRENT_DATE() - 現在の日付を返す

  • CURRENT_TIME() - Returns the current time

    CURRENT_TIME() - 現在の時刻を返す

  • CURRENT_TIMESTAMP() - Returns a timestamp of the current date and time.

    CURRENT_TIMESTAMP() - 現在の日時のタイムスタンプを返します。

  • LENGTH(str) - Returns the length of the given string

    LENGTH(str) - 指定された文字列の長さを返します

  • LOCATE(needle, haystack [, offset]) - Locate the first occurrence of the substring in the string.

    LOCATE(needle, haystack [, offset]) - 文字列内の部分文字列の最初の出現箇所を見つけます。

  • LOWER(str) - returns the string lowercased.

    LOWER(str) - 文字列を小文字にして返します。

  • MOD(a, b) - Return a MOD b.

    MOD(a, b) - MOD を返す b.

  • SIZE(collection) - Return the number of elements in the specified collection

    SIZE(collection) - 指定されたコレクションの要素数を返す

  • SQRT(q) - Return the square-root of q.

    SQRT(q) - q の平方根を返します。

  • SUBSTRING(str, start [, length]) - Return substring of given string.

    SUBSTRING(str, start [, length]) - 指定された文字列の部分文字列を返します。

  • TRIM([LEADING | TRAILING | BOTH] ['trchar' FROM] str) - Trim the string by the given trim char, defaults to whitespaces.

    TRIM([LEADING | TRAILING | BOTH] ['trchar' FROM] str) - 指定されたトリム文字で文字列をトリムします。デフォルトは空白です。

  • UPPER(str) - Return the upper-case of the given string.

    UPPER(str) - 指定された文字列の大文字を返します。

  • DATE_ADD(date, value, unit) - Add the given time to a given date. (Supported units are SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR)

    DATE_ADD(date, value, unit) - 指定された日付に指定された時間を追加します (サポートされている単位は、SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、YEAR です)。

  • DATE_SUB(date, value, unit) - Subtract the given time from a given date. (Supported units are SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR)

    DATE_SUB(date, value, unit) - 指定された日付から指定された時間を減算します。 (サポートされている単位は、SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、YEAR です)

  • DATE_DIFF(date1, date2) - Calculate the difference in days between date1-date2.

    DATE_DIFF(date1, date2) - date1-date2 の日数差を計算します。

14.6.2. Arithmetic operators

You can do math in DQL using numeric values, for example:

数値を使用して DQL で計算を行うことができます。次に例を示します。

SELECT person.salary * 1.5 FROM CompanyPerson person WHERE person.salary < 100000

14.6.3. Aggregate Functions

The following aggregate functions are allowed in SELECT and GROUP BY clauses: AVG, COUNT, MIN, MAX, SUM

次の集計関数は、SELECT 句と GROUPBY 句で使用できます: AVG、COUNT、MIN、MAX、SUM

14.6.4. Other Expressions

DQL offers a wide-range of additional expressions that are known from SQL, here is a list of all the supported constructs:

DQL は、SQL から知られている幅広い追加の式を提供します。サポートされているすべての構造のリストを次に示します。

  • ALL/ANY/SOME - Used in a WHERE clause followed by a sub-select this works like the equivalent constructs in SQL.

    ALL/ANY/SOME - サブセレクトが続く WHERE 句で使用されます。これは、SQL の同等の構文のように機能します。

  • BETWEEN a AND b and NOT BETWEEN a AND b can be used to match ranges of arithmetic values.

    BETWEEN a AND b および NOT BETWEEN a AND b を使用して、算術値の範囲を一致させることができます。

  • IN (x1, x2, ...) and NOT IN (x1, x2, ..) can be used to match a set of given values.

    IN (x1, x2, ...) および NOT IN (x1, x2, ..) を使用して、指定された値のセットを一致させることができます。

  • LIKE .. and NOT LIKE .. match parts of a string or text using % as a wildcard.

    LIKE .. および NOT LIKE .. は、% をワイルドカードとして使用して、文字列またはテキストの一部に一致します。

  • IS NULL and IS NOT NULL to check for null values

    null 値をチェックする IS NULL および IS NOT NULL

  • EXISTS and NOT EXISTS in combination with a sub-select

    副選択と組み合わせた EXISTS および NOT EXISTS

14.6.5. Adding your own functions to the DQL language

By default DQL comes with functions that are part of a large basis of underlying databases. However you will most likely choose a database platform at the beginning of your project and most likely never change it. For this cases you can easily extend the DQL parser with own specialized platform functions.

デフォルトでは、DQL には、基盤となるデータベースの大規模な基盤の一部である関数が付属しています。ただし、プロジェクトの開始時にデータベース プラットフォームを選択する可能性が高く、それを変更することはほとんどありません。この場合、DQLparser を独自の特殊なプラットフォーム関数で簡単に拡張できます。

You can register custom DQL functions in your ORM Configuration:

カスタム DQL 関数を ORM 構成に登録できます。

<?php
$config = new \Doctrine\ORM\Configuration();
$config->addCustomStringFunction($name, $class);
$config->addCustomNumericFunction($name, $class);
$config->addCustomDatetimeFunction($name, $class);

$em = new EntityManager($connection, $config);

The functions have to return either a string, numeric or datetime value depending on the registered function type. As an example we will add a MySQL specific FLOOR() functionality. All the given classes have to implement the base class :

関数は、登録された関数の型に応じて、文字列、数値、または日時値のいずれかを返す必要があります。例として、MySQL 固有の FLOOR() 機能を追加します。指定されたすべてのクラスは、基本クラスを実装する必要があります。

<?php
namespace MyProject\Query\AST;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;

class MysqlFloor extends FunctionNode
{
    public $simpleArithmeticExpression;

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return 'FLOOR(' . $sqlWalker->walkSimpleArithmeticExpression(
            $this->simpleArithmeticExpression
        ) . ')';
    }

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression();

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

We will register the function by calling and can then use it:

関数を呼び出して登録し、それを使用できるようにします。

<?php
$config = $em->getConfiguration();
$config->registerNumericFunction('FLOOR', 'MyProject\Query\MysqlFloor');

$dql = "SELECT FLOOR(person.salary * 1.75) FROM CompanyPerson person";

14.7. Querying Inherited Classes

This section demonstrates how you can query inherited classes and what type of results to expect.

このセクションでは、継承されたクラスを照会する方法と、期待される結果のタイプを示します。

14.7.1. Single Table

Single Table Inheritance is an inheritance mapping strategy where all classes of a hierarchy are mapped to a single database table. In order to distinguish which row represents which type in the hierarchy a so-called discriminator column is used.

単一テーブルの継承は、階層のすべてのクラスが単一のデータベース テーブルにマップされる継承マッピング戦略です。どの行が階層内のどのタイプを表しているかを区別するために、いわゆる識別子列が使用されます。

First we need to setup an example set of entities to use. In this scenario it is a generic Person and Employee example:

まず、使用するエンティティのサンプル セットをセットアップする必要があります。このシナリオでは、一般的な個人と従業員の例です:

<?php
namespace Entities;

#[Entity]
#[InheritanceType('SINGLE_TABLE')]
#[DiscriminatorColumn(name: 'discr', type: 'string')]
#[DiscriminatorMap(['person' => 'Person', 'employee' => 'Employee'])]
class Person
{
    #[Id, Column(type: 'integer')]
    #[GeneratedValue]
    protected int|null $id = null;

    #[Column(type: 'string', length: 50)]
    protected string $name;

    // ...
}

#[Entity]
class Employee extends Person
{
    #[Column(type: 'string', length: 50)]
    private $department;

    // ...
}

First notice that the generated SQL to create the tables for these entities looks like the following:

最初に、これらのエンティティのテーブルを作成するために生成された SQL が次のようになっていることに注意してください。

CREATE TABLE Person (
    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    name VARCHAR(50) NOT NULL,
    discr VARCHAR(255) NOT NULL,
    department VARCHAR(50) NOT NULL
)

Now when persist a new Employee instance it will set the discriminator value for us automatically:

新しい Employee インスタンスを永続化すると、識別子の値が自動的に設定されます。

<?php
$employee = new \Entities\Employee();
$employee->setName('test');
$employee->setDepartment('testing');
$em->persist($employee);
$em->flush();

Now lets run a simple query to retrieve the Employee we just created:

次に、単純なクエリを実行して、作成したばかりの Employee を取得します。

SELECT e FROM Entities\Employee e WHERE e.name = 'test'

If we check the generated SQL you will notice it has some special conditions added to ensure that we will only get back Employee entities:

生成された SQL を確認すると、Employeeentities のみが返されるようにするために、いくつかの特別な条件が追加されていることがわかります。

SELECT p0_.id AS id0, p0_.name AS name1, p0_.department AS department2,
       p0_.discr AS discr3 FROM Person p0_
WHERE (p0_.name = ?) AND p0_.discr IN ('employee')

14.7.2. Class Table Inheritance

Class Table Inheritance is an inheritance mapping strategy where each class in a hierarchy is mapped to several tables: its own table and the tables of all parent classes. The table of a child class is linked to the table of a parent class through a foreign key constraint. Doctrine ORM implements this strategy through the use of a discriminator column in the topmost table of the hierarchy because this is the easiest way to achieve polymorphic queries with Class Table Inheritance.

クラス テーブルの継承は、階層内の各クラスが複数のテーブル (独自のテーブルとすべての親クラスのテーブル) にマップされる継承マッピング戦略です。子クラスのテーブルは、外部キー制約を通じて親クラスのテーブルにリンクされています。 Doctrine ORM は、階層の最上位のテーブルにある識別子列を使用してこの戦略を実装します。これは、クラス テーブルの継承を使用してポリモーフィック クエリを実現する最も簡単な方法だからです。

The example for class table inheritance is the same as single table, you just need to change the inheritance type from SINGLE_TABLE to JOINED:

クラス テーブルの継承の例は、singletable と同じです。継承タイプを SINGLE_TABLE から JOINED に変更するだけです。

<?php

#[Entity]
#[InheritanceType('JOINED')]
#[DiscriminatorColumn(name: 'discr', type: 'string')]
#[DiscriminatorMap(['person' => 'Person', 'employee' => 'Employee'])]
class Person
{
    // ...
}

Now take a look at the SQL which is generated to create the table, you’ll notice some differences:

ここで、テーブルを作成するために生成された SQL を見てみましょう。いくつかの違いに気付くでしょう。

CREATE TABLE Person (
    id INT AUTO_INCREMENT NOT NULL,
    name VARCHAR(50) NOT NULL,
    discr VARCHAR(255) NOT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB;
CREATE TABLE Employee (
    id INT NOT NULL,
    department VARCHAR(50) NOT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB;
ALTER TABLE Employee ADD FOREIGN KEY (id) REFERENCES Person(id) ON DELETE CASCADE
  • The data is split between two tables

    データは 2 つのテーブルに分割されます

  • A foreign key exists between the two tables

    2 つのテーブル間に外部キーが存在する

Now if were to insert the same Employee as we did in the SINGLE_TABLE example and run the same example query it will generate different SQL joining the Person information automatically for you:

ここで、SINGLE_TABLE の例で行ったのと同じ従業員を挿入し、同じサンプル クエリを実行すると、Person 情報を自動的に結合する別の SQL が生成されます。

SELECT p0_.id AS id0, p0_.name AS name1, e1_.department AS department2,
       p0_.discr AS discr3
FROM Employee e1_ INNER JOIN Person p0_ ON e1_.id = p0_.id
WHERE p0_.name = ?

14.8. The Query class

An instance of the Doctrine\ORM\Query class represents a DQL query. You create a Query instance be calling EntityManager#createQuery($dql), passing the DQL query string. Alternatively you can create an empty Query instance and invoke Query#setDQL($dql) afterwards. Here are some examples:

Doctrine\ORM\Query クラスのインスタンスは、DQLquery を表します。 CallingEntityManager#createQuery($dql) で Query インスタンスを作成し、DQL クエリ文字列を渡します。または、空の Query インスタンスを作成し、後で Query#setDQL($dql) を呼び出すこともできます。ここではいくつかの例を示します。

<?php
// $em instanceof EntityManager

// example1: passing a DQL string
$q = $em->createQuery('select u from MyProject\Model\User u');

// example2: using setDQL
$q = $em->createQuery();
$q->setDQL('select u from MyProject\Model\User u');

14.8.1. Query Result Formats

The format in which the result of a DQL SELECT query is returned can be influenced by a so-called hydration mode. A hydration mode specifies a particular way in which a SQL result set is transformed. Each hydration mode has its own dedicated method on the Query class. Here they are:

DQL SELECT クエリの結果が返される形式は、いわゆるハイドレーション モードの影響を受ける可能性があります。ハイドレーションモードは、SQL 結果セットが変換される特定の方法を指定します。各ハイドレーション モードには、Query クラスに専用のメソッドがあります。はい、どうぞ:

  • Query#getResult(): Retrieves a collection of objects. The result is either a plain collection of objects (pure) or an array where the objects are nested in the result rows (mixed).

    Query#getResult(): オブジェクトのコレクションを取得します。結果は、オブジェクトの単純なコレクション (pure) またはオブジェクトが結果行にネストされている配列 (mixed) のいずれかです。

  • Query#getSingleResult(): Retrieves a single object. If the result contains more than one object, an NonUniqueResultException is thrown. If the result contains no objects, an NoResultException is thrown. The pure/mixed distinction does not apply.

    Query#getSingleResult(): 単一のオブジェクトを取得します。結果に複数のオブジェクトが含まれる場合、NonUniqueResultException がスローされます。結果にオブジェクトが含まれていない場合は、NoResultException がスローされます。純粋/混合の区別は適用されません。

  • Query#getOneOrNullResult(): Retrieve a single object. If the result contains more than one object, a NonUniqueResultException is thrown. If no object is found null will be returned.

    Query#getOneOrNullResult(): 単一のオブジェクトを取得します。結果に複数のオブジェクトが含まれる場合、NonUniqueResultException がスローされます。オブジェクトが見つからない場合は null が返されます。

  • Query#getArrayResult(): Retrieves an array graph (a nested array) that is largely interchangeable with the object graph generated by Query#getResult() for read-only purposes.

    Query#getArrayResult(): 読み取り専用の目的で Query#getResult() によって生成されたオブジェクト グラフとほとんど交換可能な配列グラフ (ネストされた配列) を取得します。

    Note

    ノート

    An array graph can differ from the corresponding object graph in certain scenarios due to the difference of the identity semantics between arrays and objects.

    配列グラフは、配列とオブジェクト間の同一性セマンティクスの違いにより、特定のシナリオで対応する objectgraph と異なる場合があります。

  • Query#getScalarResult(): Retrieves a flat/rectangular result set of scalar values that can contain duplicate data. The pure/mixed distinction does not apply.

    Query#getScalarResult(): 重複データを含む可能性があるスカラー値のフラット/長方形の結果セットを取得します。純粋/混合の区別は適用されません。

  • Query#getSingleScalarResult(): Retrieves a single scalar value from the result returned by the dbms. If the result contains more than a single scalar value, an exception is thrown. The pure/mixed distinction does not apply.

    Query#getSingleScalarResult(): dbms によって返された結果から単一のスカラー値を取得します。結果に複数のスカラー値が含まれる場合、例外がスローされます。純粋/混合の区別は適用されません。

Instead of using these methods, you can alternatively use the general-purpose method Query#execute(array $params = [], $hydrationMode = Query::HYDRATE_OBJECT). Using this method you can directly supply the hydration mode as the second parameter via one of the Query constants. In fact, the methods mentioned earlier are just convenient shortcuts for the execute method. For example, the method Query#getResult() internally invokes execute, passing in Query::HYDRATE_OBJECT as the hydration mode.

これらのメソッドを使用する代わりに、汎用メソッド Query#execute(array $params = [], $hydrationMode = Query::HYDRATE_OBJECT) を使用することもできます。このメソッドを使用すると、ハイドレーション モードを第 2 パラメーターとして、クエリ定数。実際、前述のメソッドは、execute メソッドの便利なショートカットにすぎません。たとえば、メソッド Query#getResult() は内部的に実行を呼び出し、ハイドレーション モードとして Query::HYDRATE_OBJECT を渡します。

The use of the methods mentioned earlier is generally preferred as it leads to more concise code.

前述のメソッドの使用は、より簡潔なコードにつながるため、一般的に好まれます。

14.8.2. Pure and Mixed Results

The nature of a result returned by a DQL SELECT query retrieved through Query#getResult() or Query#getArrayResult() can be of 2 forms: pure and mixed. In the previous simple examples, you already saw a “pure” query result, with only objects. By default, the result type is pure but as soon as scalar values, such as aggregate values or other scalar values that do not belong to an entity, appear in the SELECT part of the DQL query, the result becomes mixed. A mixed result has a different structure than a pure result in order to accommodate for the scalar values.

Query#getResult() または Query#getArrayResult() を介して取得された DQL SELECT クエリによって返される結果の性質には、純粋と混合の 2 つの形式があります。前の単純な例では、オブジェクトのみを含む「純粋な」クエリ結果を既に見ました。デフォルトでは、結果の型は純粋ですが、エンティティに属さない集計値やその他のスカラー値などのスカラー値が表示されるとすぐに表示されます。 DQL クエリの SELECT 部分では、結果が混合になります。混合結果は、スカラー値に対応するために、純粋な結果とは異なる構造を持ちます。

A pure result usually looks like this:

通常、純粋な結果は次のようになります。

$dql = "SELECT u FROM User u";

array
    [0] => Object
    [1] => Object
    [2] => Object
    ...

A mixed result on the other hand has the following general structure:

一方、混合結果には次の一般的な構造があります。

$dql = "SELECT u, 'some scalar string', count(g.id) AS num FROM User u JOIN u.groups g GROUP BY u.id";

array
    [0]
        [0] => Object
        [1] => "some scalar string"
        ['num'] => 42
        // ... more scalar values, either indexed numerically or with a name
    [1]
        [0] => Object
        [1] => "some scalar string"
        ['num'] => 42
        // ... more scalar values, either indexed numerically or with a name

To better understand mixed results, consider the following DQL query:

混合結果をよりよく理解するには、次の DQLquery を検討してください。

SELECT u, UPPER(u.name) nameUpper FROM MyProject\Model\User u

This query makes use of the UPPER DQL function that returns a scalar value and because there is now a scalar value in the SELECT clause, we get a mixed result.

このクエリは、アスカラー値を返す UPPER DQL 関数を使用します。SELECT 句にスカラー値が含まれるようになったため、さまざまな結果が得られます。

Conventions for mixed results are as follows:

混合結果の規則は次のとおりです。

  • The object fetched in the FROM clause is always positioned with the key ‘0’.

    FROM 句でフェッチされたオブジェクトは、常にキー「0」で配置されます。

  • Every scalar without a name is numbered in the order given in the query, starting with 1.

    名前のないすべてのスカラーには、クエリで指定された順序で 1 から始まる番号が付けられます。

  • Every aliased scalar is given with its alias-name as the key. The case of the name is kept.

    エイリアスが設定されたすべてのスカラーは、そのエイリアス名をキーとして指定されます。名前の大文字と小文字は保持されます。

  • If several objects are fetched from the FROM clause they alternate every row.

    FROM 句から複数のオブジェクトがフェッチされる場合、それらはすべての行を交互に切り替えます。

Here is how the result could look like:

結果は次のようになります。

array
    array
        [0] => User (Object)
        ['nameUpper'] => "ROMAN"
    array
        [0] => User (Object)
        ['nameUpper'] => "JONATHAN"
    ...

And here is how you would access it in PHP code:

PHPコードでアクセスする方法は次のとおりです。

<?php
foreach ($results as $row) {
    echo "Name: " . $row[0]->getName();
    echo "Name UPPER: " . $row['nameUpper'];
}

14.8.3. Fetching Multiple FROM Entities

If you fetch multiple entities that are listed in the FROM clause then the hydration will return the rows iterating the different top-level entities.

FROM 句にリストされている複数のエンティティをフェッチすると、ハイドレーションはさまざまな最上位エンティティを反復する行を返します。

$dql = "SELECT u, g FROM User u, Group g";

array
    [0] => Object (User)
    [1] => Object (Group)
    [2] => Object (User)
    [3] => Object (Group)

14.8.4. Hydration Modes

Each of the Hydration Modes makes assumptions about how the result is returned to user land. You should know about all the details to make best use of the different result formats:

各ハイドレーション モードは、結果がユーザー ランドに返される方法について仮定を行います。さまざまな結果形式を最大限に活用するには、すべての詳細について知っておく必要があります。

The constants for the different hydration modes are:

異なる水分補給モードの定数は次のとおりです。

  • Query::HYDRATE_OBJECT

    クエリ::HYDRATE_OBJECT

  • Query::HYDRATE_ARRAY

    クエリ::HYDRATE_ARRAY

  • Query::HYDRATE_SCALAR

    クエリ::HYDRATE_SCALAR

  • Query::HYDRATE_SINGLE_SCALAR

    クエリ::HYDRATE_SINGLE_SCALAR

  • Query::HYDRATE_SCALAR_COLUMN

    クエリ::HYDRATE_SCALAR_COLUMN

14.8.4.1. Object Hydration

Object hydration hydrates the result set into the object graph:

オブジェクトのハイドレーションは、結果セットをオブジェクト グラフにハイドレートします。

<?php
$query = $em->createQuery('SELECT u FROM CmsUser u');
$users = $query->getResult(Query::HYDRATE_OBJECT);

Sometimes the behavior in the object hydrator can be confusing, which is why we are listing as many of the assumptions here for reference:

オブジェクト ハイドレーターの動作が混乱を招くことがあります。そのため、参照用にここに多くの仮定をリストしています。

  • Objects fetched in a FROM clause are returned as a Set, that means every object is only ever included in the resulting array once. This is the case even when using JOIN or GROUP BY in ways that return the same row for an object multiple times. If the hydrator sees the same object multiple times, then it makes sure it is only returned once.

    FROM 句でフェッチされたオブジェクトはセットとして返されます。つまり、すべてのオブジェクトが結果の配列に一度だけ含まれます。これは、オブジェクトに対して同じ行を複数回返す方法で JOIN または GROUP BY を使用する場合でも当てはまります。ハイドレーターが同じオブジェクトを複数回見た場合、一度だけ返されるようにします。

  • If an object is already in memory from a previous query of any kind, then then the previous object is used, even if the database may contain more recent data. Data from the database is discarded. This even happens if the previous object is still an unloaded proxy.

    オブジェクトが何らかの種類の以前のクエリから既にメモリ内にある場合、データベースにさらに新しいデータが含まれている場合でも、以前のオブジェクトが使用されます。データベースからのデータは破棄されます。これは、前のオブジェクトがまだアンロードされたプロキシである場合にも発生します。

This list might be incomplete.

このリストは不完全な場合があります。

14.8.4.2. Array Hydration

You can run the same query with array hydration and the result set is hydrated into an array that represents the object graph:

配列ハイドレーションを使用して同じクエリを実行すると、結果セットがオブジェクト グラフを表す配列にハイドレートされます。

<?php
$query = $em->createQuery('SELECT u FROM CmsUser u');
$users = $query->getResult(Query::HYDRATE_ARRAY);

You can use the getArrayResult() shortcut as well:

getArrayResult() ショートカットも使用できます。

<?php
$users = $query->getArrayResult();

14.8.4.3. Scalar Hydration

If you want to return a flat rectangular result set instead of an object graph you can use scalar hydration:

オブジェクト グラフの代わりに平らな長方形の結果セットを返したい場合は、スカラー水和を使用できます。

<?php
$query = $em->createQuery('SELECT u FROM CmsUser u');
$users = $query->getResult(Query::HYDRATE_SCALAR);
echo $users[0]['u_id'];

The following assumptions are made about selected fields using Scalar Hydration:

Scalar Hydration を使用して、選択したフィールドについて次の仮定が行われます。

  1. Fields from classes are prefixed by the DQL alias in the result. A query of the kind ‘SELECT u.name ..’ returns a key ‘u_name’ in the result rows.

    クラスのフィールドには、結果の DQL エイリアスが接頭辞として付けられます。種類「SELECT u.name ..」のクエリは、結果行にキー「u_name」を返します。

14.8.4.4. Single Scalar Hydration

If you have a query which returns just a single scalar value you can use single scalar hydration:

単一のスカラー値のみを返すクエリがある場合は、単一のスカラー ハイドレーションを使用できます。

<?php
$query = $em->createQuery('SELECT COUNT(a.id) FROM CmsUser u LEFT JOIN u.articles a WHERE u.username = ?1 GROUP BY u.id');
$query->setParameter(1, 'jwage');
$numArticles = $query->getResult(Query::HYDRATE_SINGLE_SCALAR);

You can use the getSingleScalarResult() shortcut as well:

getSingleScalarResult() ショートカットも使用できます。

<?php
$numArticles = $query->getSingleScalarResult();

14.8.4.5. Scalar Column Hydration

If you have a query which returns a one-dimensional array of scalar values you can use scalar column hydration:

スカラー値の 1 次元配列を返すクエリがある場合は、スカラー列のハイドレーションを使用できます。

<?php
$query = $em->createQuery('SELECT a.id FROM CmsUser u');
$ids = $query->getResult(Query::HYDRATE_SCALAR_COLUMN);

You can use the getSingleColumnResult() shortcut as well:

getSingleColumnResult() ショートカットも使用できます。

<?php
$ids = $query->getSingleColumnResult();

14.8.4.6. Custom Hydration Modes

You can easily add your own custom hydration modes by first creating a class which extends AbstractHydrator:

AbstractHydrator を拡張するクラスを最初に作成することにより、独自のカスタム ハイドレーション モードを簡単に追加できます。

<?php
namespace MyProject\Hydrators;

use Doctrine\DBAL\FetchMode;
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;

class CustomHydrator extends AbstractHydrator
{
    protected function _hydrateAll()
    {
        return $this->_stmt->fetchAll(FetchMode::FETCH_ASSOC);
    }
}

Next you just need to add the class to the ORM configuration:

次に、クラスを ORM 構成に追加する必要があります。

<?php
$em->getConfiguration()->addCustomHydrationMode('CustomHydrator', 'MyProject\Hydrators\CustomHydrator');

Now the hydrator is ready to be used in your queries:

これでハイドレーターをクエリで使用する準備が整いました:

<?php
$query = $em->createQuery('SELECT u FROM CmsUser u');
$results = $query->getResult('CustomHydrator');

14.8.5. Iterating Large Result Sets

There are situations when a query you want to execute returns a very large result-set that needs to be processed. All the previously described hydration modes completely load a result-set into memory which might not be feasible with large result sets. See the Batch Processing section on details how to iterate large result sets.

実行したいクエリが、処理が必要な非常に大きな結果セットを返す場合があります。前述のハイドレーション モードはすべて、結果セットをメモリに完全にロードしますが、大きな結果セットでは実行できない場合があります。大きな結果セットを反復処理する方法の詳細については、バッチ処理セクションを参照してください。

14.8.6. Functions

The following methods exist on the AbstractQuery which both Query and NativeQuery extend from.

以下のメソッドは、両方の Query と NativeQuery の拡張元である AbstractQuery に存在します。

14.8.6.1. Parameters

Prepared Statements that use numerical or named wildcards require additional parameters to be executable against the database. To pass parameters to the query the following methods can be used:

数値または名前付きのワイルドカードを使用するプリペアド ステートメントでは、データベースに対して実行できる追加のパラメーターが必要です。パラメータをクエリに渡すには、次のメソッドを使用できます。

  • AbstractQuery::setParameter($param, $value) - Set the numerical or named wildcard to the given value.

    AbstractQuery::setParameter($param, $value) - 数値または名前付きワイルドカードを指定された値に設定します。

  • AbstractQuery::setParameters(array $params) - Set an array of parameter key-value pairs.

    AbstractQuery::setParameters(array $params) - パラメータのキーと値のペアの配列を設定します。

  • AbstractQuery::getParameter($param)

    AbstractQuery::getParameter($param)

  • AbstractQuery::getParameters()

    AbstractQuery::getParameters()

Both named and positional parameters are passed to these methods without their ? or : prefix.

名前付きパラメーターと位置パラメーターの両方が、? なしでこれらのメソッドに渡されます。または : プレフィックス。

14.8.6.3. Query Hints

You can pass hints to the query parser and hydrators by using the AbstractQuery::setHint($name, $value) method. Currently there exist mostly internal query hints that are not be consumed in userland. However the following few hints are to be used in userland:

AbstractQuery::setHint($name, $value) メソッドを使用して、クエリ パーサーとハイドレーターにヒントを渡すことができます。現在、ユーザーランドで消費されないほとんどの内部クエリヒントが存在します。ただし、次のいくつかのヒントはユーザーランドで使用する必要があります。

  • Query::HINT_FORCE_PARTIAL_LOAD - Allows to hydrate objects although not all their columns are fetched. This query hint can be used to handle memory consumption problems with large result-sets that contain char or binary data. Doctrine has no way of implicitly reloading this data. Partially loaded objects have to be passed to EntityManager::refresh() if they are to be reloaded fully from the database. This query hint is deprecated and will be removed in the future (Details)

    Query::HINT_FORCE_PARTIAL_LOAD - すべての列がフェッチされるわけではありませんが、オブジェクトをハイドレートできます。このクエリ ヒントは、char またはバイナリ データを含む大きな結果セットでのメモリ消費の問題を処理するために使用できます。 Doctrine には、このデータを暗黙的にリロードする方法がありません。部分的にロードされたオブジェクトは、データベースから完全に再ロードする場合、EntityManager::refresh() に渡す必要があります。このクエリ ヒントは非推奨であり、今後削除される予定です (詳細)

  • Query::HINT_REFRESH - This query is used internally by EntityManager::refresh() and can be used in userland as well. If you specify this hint and a query returns the data for an entity that is already managed by the UnitOfWork, the fields of the existing entity will be refreshed. In normal operation a result-set that loads data of an already existing entity is discarded in favor of the already existing entity.

    Query::HINT_REFRESH - このクエリは EntityManager::refresh() によって内部的に使用され、ユーザーランドでも使用できます。このヒントを指定し、クエリが UnitOfWork によって既に管理されているエンティティのデータを返す場合、既存のフィールドエンティティが更新されます。通常の操作では、既存のエンティティのデータをロードする結果セットは破棄され、既存のエンティティが優先されます。

  • Query::HINT_CUSTOM_TREE_WALKERS - An array of additional Doctrine\ORM\Query\TreeWalker instances that are attached to the DQL query parsing process.

    Query::HINT_CUSTOM_TREE_WALKERS - DQL クエリ解析プロセスにアタッチされた追加のDoctrine\ORM\Query\TreeWalker インスタンスの配列。

14.8.6.4. Query Cache (DQL Query Only)

Parsing a DQL query and converting it into a SQL query against the underlying database platform obviously has some overhead in contrast to directly executing Native SQL queries. That is why there is a dedicated Query Cache for caching the DQL parser results. In combination with the use of wildcards you can reduce the number of parsed queries in production to zero.

DQL クエリを解析し、それを基盤となるデータベース プラットフォームに対する SQL クエリに変換すると、ネイティブ SQL クエリを直接実行する場合とは対照的に、明らかにオーバーヘッドが発生します。そのため、DQL パーサーの結果をキャッシュするための専用のクエリ キャッシュがあります。ワイルドカードの使用と組み合わせて、本番環境で解析されるクエリの数をゼロに減らすことができます。

The Query Cache Driver is passed from the Doctrine\ORM\Configuration instance to each Doctrine\ORM\Query instance by default and is also enabled by default. This also means you don’t regularly need to fiddle with the parameters of the Query Cache, however if you do there are several methods to interact with it:

Query Cache Driver は、Doctrine\ORM\Configuration インスタンスから各Doctrine\ORM\Query インスタンスにデフォルトで渡され、デフォルトで有効になっています。これは、定期的にクエリ キャッシュのパラメータをいじる必要がないことも意味しますが、そうする場合は、それを操作する方法がいくつかあります。

  • Query::setQueryCacheDriver($driver) - Allows to set a Cache instance

    Query::setQueryCacheDriver($driver) - Cacheinstance を設定できるようにする

  • Query::setQueryCacheLifeTime($seconds = 3600) - Set lifetime of the query caching.

    Query::setQueryCacheLifeTime($seconds = 3600) - クエリ キャッシュの有効期間を設定します。

  • Query::expireQueryCache($bool) - Enforce the expiring of the query cache if set to true.

    Query::expireQueryCache($bool) - true に設定されている場合、クエリ キャッシュの期限切れを強制します。

  • Query::getExpireQueryCache()

    クエリ::getExpireQueryCache()

  • Query::getQueryCacheDriver()

    クエリ::getQueryCacheDriver()

  • Query::getQueryCacheLifeTime()

    クエリ::getQueryCacheLifeTime()

14.8.6.5. First and Max Result Items (DQL Query Only)

You can limit the number of results returned from a DQL query as well as specify the starting offset, Doctrine then uses a strategy of manipulating the select query to return only the requested number of results:

DQL クエリから返される結果の数を制限することも、開始オフセットを指定することもできます。Doctrine は選択クエリを操作する戦略を使用して、要求された数の結果のみを返します。

  • Query::setMaxResults($maxResults)

    Query::setMaxResults($maxResults)

  • Query::setFirstResult($offset)

    Query::setFirstResult($offset)

Note

ノート

If your query contains a fetch-joined collection specifying the result limit methods are not working as you would expect. Set Max Results restricts the number of database result rows, however in the case of fetch-joined collections one root entity might appear in many rows, effectively hydrating less than the specified number of results.

クエリに fetch-joined コレクションが含まれている場合、結果制限メソッドを指定すると、期待どおりに機能しません。 Set Max Results はデータベースの結果行の数を制限しますが、フェッチ結合されたコレクションの場合、1 つのルート エンティティが多くの行に表示され、指定された結果数より少ない数の結果を効果的にハイドレートする可能性があります。

14.8.6.6. Temporarily change fetch mode in DQL

While normally all your associations are marked as lazy or extra lazy you will have cases where you are using DQL and don’t want to fetch join a second, third or fourth level of entities into your result, because of the increased cost of the SQL JOIN. You can mark a many-to-one or one-to-one association as fetched temporarily to batch fetch these entities using a WHERE .. IN query.

通常、すべてのアソシエーションはレイジーまたはエクストラ レイジーとしてマークされますが、SQL JOIN のコストが増加するため、DQL を使用していて、エンティティの 2 番目、3 番目、または 4 番目のレベルのエンティティを結果に結合したくない場合があります。 .多対 1 または 1 対 1 の関連付けを一時的にフェッチ済みとしてマークし、WHERE .. IN クエリを使用してこれらのエンティティをバッチ フェッチできます。

<?php
$query = $em->createQuery("SELECT u FROM MyProject\User u");
$query->setFetchMode("MyProject\User", "address", \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER);
$query->execute();

Given that there are 10 users and corresponding addresses in the database the executed queries will look something like:

データベースに 10 人のユーザーと対応するアドレスがあるとすると、実行されたクエリは次のようになります。

SELECT * FROM users;
SELECT * FROM address WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Note

ノート

Changing the fetch mode during a query mostly makes sense for one-to-one and many-to-one relations. In that case, all the necessary IDs are available after the root entity (user in the above example) has been loaded. So, one query per association can be executed to fetch all the referred-to entities (address).

クエリ中にフェッチ モードを変更することは、ほとんどの場合、1 対 1 および多対 1 の関係で意味があります。その場合、必要なすべての ID は、ルート エンティティ (上記の例ではユーザー) が読み込まれた後に使用できます。したがって、アソシエーションごとに 1 つのクエリを実行して、参照先のすべてのエンティティ (アドレス) を取得できます。

For one-to-many relations, changing the fetch mode to eager will cause to execute one query for every root entity loaded. This gives no improvement over the lazy fetch mode which will also initialize the associations on a one-by-one basis once they are accessed.

1 対多の関係の場合、フェッチ モードを熱心に変更すると、読み込まれたルート エンティティごとに 1 つのクエリが実行されます。これは、アクセスされると関連付けを 1 つずつ初期化する遅延フェッチ モードよりも改善されません。

14.9. EBNF

The following context-free grammar, written in an EBNF variant, describes the Doctrine Query Language. You can consult this grammar whenever you are unsure about what is possible with DQL or what the correct syntax for a particular query should be.

以下の文脈自由文法は、EBNF バリアントで書かれており、Doctrine Query Language を記述しています。 DQL で何ができるのか、特定のクエリの正しい構文がどうあるべきかがわからない場合は、いつでもこの文法を参照できます。

14.9.1. Document syntax:

  • non-terminals begin with an upper case character

    非終端記号は大文字で始まります

  • terminals begin with a lower case character

    ターミナルは小文字で始まります

  • parentheses (…) are used for grouping

    括弧 (…) はグループ化に使用されます

  • square brackets […] are used for defining an optional part, e.g. zero or one time

    角括弧 […] は、オプションの部分を定義するために使用されます。ゼロまたは1回

  • curly brackets {…} are used for repetition, e.g. zero or more times

    中括弧 {…} は繰り返しに使用されます。ゼロ回以上

  • double quotation marks “…” define a terminal string

    二重引用符「…」は終端文字列を定義します

  • a vertical bar | represents an alternative

    縦棒 |代替を表す

14.9.2. Terminals

  • identifier (name, email, …) must match [a-z_][a-z0-9_]*

    識別子 (名前、電子メールなど) は [a-z_][a-z0-9_] と一致する必要があります*

  • fully_qualified_name (DoctrineTestsModelsCMSCmsUser) matches PHP’s fully qualified class names

    fully_qualified_name (DoctrineTestsModelsCMSCmsUser) は PHP の完全修飾クラス名と一致します

  • string (‘foo’, ‘bar’’s house’, ‘%ninja%’, …)

    文字列 ('foo'、'bar''s house'、'%ninja%'、…)

  • char (‘/’, ‘\’, ‘ ‘, …)

    文字 (「/」、「\」、「」、…)

  • integer (-1, 0, 1, 34, …)

    整数 (-1、0、1、34、…)

  • float (-0.23, 0.007, 1.245342E+8, …)

    フロート (-0.23、0.007、1.245342E+8、…)

  • boolean (false, true)

    ブール値 (偽、真)

14.9.3. Query Language

QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement

14.9.4. Statements

SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
UpdateStatement ::= UpdateClause [WhereClause]
DeleteStatement ::= DeleteClause [WhereClause]

14.9.5. Identifiers

/* Alias Identification usage (the "u" of "u.name") */
IdentificationVariable ::= identifier

/* Alias Identification declaration (the "u" of "FROM User u") */
AliasIdentificationVariable :: = identifier

/* identifier that must be a class name (the "User" of "FROM User u"), possibly as a fully qualified class name or namespace-aliased */
AbstractSchemaName ::= fully_qualified_name | aliased_name | identifier

/* Alias ResultVariable declaration (the "total" of "COUNT(*) AS total") */
AliasResultVariable = identifier

/* ResultVariable identifier usage of mapped field aliases (the "total" of "COUNT(*) AS total") */
ResultVariable = identifier

/* identifier that must be a field (the "name" of "u.name") */
/* This is responsible to know if the field exists in Object, no matter if it's a relation or a simple field */
FieldIdentificationVariable ::= identifier

/* identifier that must be a collection-valued association field (to-many) (the "Phonenumbers" of "u.Phonenumbers") */
CollectionValuedAssociationField ::= FieldIdentificationVariable

/* identifier that must be a single-valued association field (to-one) (the "Group" of "u.Group") */
SingleValuedAssociationField ::= FieldIdentificationVariable

/* identifier that must be an embedded class state field */
EmbeddedClassStateField ::= FieldIdentificationVariable

/* identifier that must be a simple state field (name, email, ...) (the "name" of "u.name") */
/* The difference between this and FieldIdentificationVariable is only semantical, because it points to a single field (not mapping to a relation) */
SimpleStateField ::= FieldIdentificationVariable

14.9.6. Path Expressions

/* "u.Group" or "u.Phonenumbers" declarations */
JoinAssociationPathExpression             ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField)

/* "u.Group" or "u.Phonenumbers" usages */
AssociationPathExpression                 ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression

/* "u.name" or "u.Group" */
SingleValuedPathExpression                ::= StateFieldPathExpression | SingleValuedAssociationPathExpression

/* "u.name" or "u.Group.name" */
StateFieldPathExpression                  ::= IdentificationVariable "." StateField

/* "u.Group" */
SingleValuedAssociationPathExpression     ::= IdentificationVariable "." SingleValuedAssociationField

/* "u.Group.Permissions" */
CollectionValuedPathExpression            ::= IdentificationVariable "." CollectionValuedAssociationField

/* "name" */
StateField                                ::= {EmbeddedClassStateField "."}* SimpleStateField

14.9.7. Clauses

SelectClause        ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}*
SimpleSelectClause  ::= "SELECT" ["DISTINCT"] SimpleSelectExpression
UpdateClause        ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}*
DeleteClause        ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariable
FromClause          ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*
SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
WhereClause         ::= "WHERE" ConditionalExpression
HavingClause        ::= "HAVING" ConditionalExpression
GroupByClause       ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*
OrderByClause       ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
Subselect           ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]

14.9.8. Items

UpdateItem  ::= SingleValuedPathExpression "=" NewValue
OrderByItem ::= (SimpleArithmeticExpression | SingleValuedPathExpression | ScalarExpression | ResultVariable | FunctionDeclaration) ["ASC" | "DESC"]
GroupByItem ::= IdentificationVariable | ResultVariable | SingleValuedPathExpression
NewValue    ::= SimpleArithmeticExpression | "NULL"

14.9.9. From, Join and Index by

IdentificationVariableDeclaration          ::= RangeVariableDeclaration [IndexBy] {Join}*
SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration
RangeVariableDeclaration                   ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
JoinAssociationDeclaration                 ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]
Join                                       ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" (JoinAssociationDeclaration | RangeVariableDeclaration) ["WITH" ConditionalExpression]
IndexBy                                    ::= "INDEX" "BY" SingleValuedPathExpression

14.9.10. Select Expressions

SelectExpression        ::= (IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression) [["AS"] ["HIDDEN"] AliasResultVariable]
SimpleSelectExpression  ::= (StateFieldPathExpression | IdentificationVariable | FunctionDeclaration | AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
PartialFieldSet         ::= "{" SimpleStateField {"," SimpleStateField}* "}"
NewObjectExpression     ::= "NEW" AbstractSchemaName "(" NewObjectArg {"," NewObjectArg}* ")"
NewObjectArg            ::= ScalarExpression | "(" Subselect ")"

14.9.11. Conditional Expressions

ConditionalExpression       ::= ConditionalTerm {"OR" ConditionalTerm}*
ConditionalTerm             ::= ConditionalFactor {"AND" ConditionalFactor}*
ConditionalFactor           ::= ["NOT"] ConditionalPrimary
ConditionalPrimary          ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
SimpleConditionalExpression ::= ComparisonExpression | BetweenExpression | LikeExpression |
                                InExpression | NullComparisonExpression | ExistsExpression |
                                EmptyCollectionComparisonExpression | CollectionMemberExpression |
                                InstanceOfExpression

14.9.12. Collection Expressions

EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
CollectionMemberExpression          ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression

14.9.13. Literal Values

Literal     ::= string | char | integer | float | boolean
InParameter ::= ArithmeticExpression | InputParameter

14.9.14. Input Parameter

InputParameter      ::= PositionalParameter | NamedParameter
PositionalParameter ::= "?" integer
NamedParameter      ::= ":" string

14.9.15. Arithmetic Expressions

ArithmeticExpression       ::= SimpleArithmeticExpression | "(" Subselect ")"
SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}*
ArithmeticTerm             ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}*
ArithmeticFactor           ::= [("+" | "-")] ArithmeticPrimary
ArithmeticPrimary          ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")"
                               | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings
                               | FunctionsReturningDatetime | IdentificationVariable | ResultVariable
                               | InputParameter | CaseExpression

14.9.16. Scalar and Type Expressions

ScalarExpression       ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary | StateFieldPathExpression | BooleanPrimary | CaseExpression | InstanceOfExpression
StringExpression       ::= StringPrimary | ResultVariable | "(" Subselect ")"
StringPrimary          ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression | CaseExpression
BooleanExpression      ::= BooleanPrimary | "(" Subselect ")"
BooleanPrimary         ::= StateFieldPathExpression | boolean | InputParameter
EntityExpression       ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
SimpleEntityExpression ::= IdentificationVariable | InputParameter
DatetimeExpression     ::= DatetimePrimary | "(" Subselect ")"
DatetimePrimary        ::= StateFieldPathExpression | InputParameter | FunctionsReturningDatetime | AggregateExpression

Note

ノート

Parts of CASE expressions are not yet implemented.

CASE 式の一部はまだ実装されていません。

14.9.17. Aggregate Expressions

AggregateExpression ::= ("AVG" | "MAX" | "MIN" | "SUM" | "COUNT") "(" ["DISTINCT"] SimpleArithmeticExpression ")"

14.9.18. Case Expressions

CaseExpression        ::= GeneralCaseExpression | SimpleCaseExpression | CoalesceExpression | NullifExpression
GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END"
WhenClause            ::= "WHEN" ConditionalExpression "THEN" ScalarExpression
SimpleCaseExpression  ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END"
CaseOperand           ::= StateFieldPathExpression | TypeDiscriminator
SimpleWhenClause      ::= "WHEN" ScalarExpression "THEN" ScalarExpression
CoalesceExpression    ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")"
NullifExpression      ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")"

14.9.19. Other Expressions

QUANTIFIED/BETWEEN/COMPARISON/LIKE/NULL/EXISTS

数量化/間/比較/類似/NULL/存在

QuantifiedExpression     ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"
BetweenExpression        ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression
ComparisonExpression     ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression )
InExpression             ::= ArithmeticExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"
InstanceOfExpression     ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")")
InstanceOfParameter      ::= AbstractSchemaName | InputParameter
LikeExpression           ::= StringExpression ["NOT"] "LIKE" StringPrimary ["ESCAPE" char]
NullComparisonExpression ::= (InputParameter | NullIfExpression | CoalesceExpression | AggregateExpression | FunctionDeclaration | IdentificationVariable | SingleValuedPathExpression | ResultVariable) "IS" ["NOT"] "NULL"
ExistsExpression         ::= ["NOT"] "EXISTS" "(" Subselect ")"
ComparisonOperator       ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="

14.9.20. Functions

FunctionDeclaration ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDateTime

FunctionsReturningNumerics ::=
        "LENGTH" "(" StringPrimary ")" |
        "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" |
        "ABS" "(" SimpleArithmeticExpression ")" |
        "SQRT" "(" SimpleArithmeticExpression ")" |
        "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
        "SIZE" "(" CollectionValuedPathExpression ")" |
        "DATE_DIFF" "(" ArithmeticPrimary "," ArithmeticPrimary ")" |
        "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")" |
        "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")"

FunctionsReturningDateTime ::=
        "CURRENT_DATE" |
        "CURRENT_TIME" |
        "CURRENT_TIMESTAMP" |
        "DATE_ADD" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")" |
        "DATE_SUB" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")"

FunctionsReturningStrings ::=
        "CONCAT" "(" StringPrimary "," StringPrimary ")" |
        "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
        "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" |
        "LOWER" "(" StringPrimary ")" |
        "UPPER" "(" StringPrimary ")" |
        "IDENTITY" "(" SingleValuedAssociationPathExpression {"," string} ")"

Table Of Contents

Previous topic

13. Batch Processing

13. バッチ処理

Next topic

15. The QueryBuilder

15. QueryBuilder

This Page

Fork me on GitHub