1
0
mirror of synced 2025-01-31 04:21:44 +03:00

Merge pull request #88 from FabioBatSilva/patch-7

Docs for Named Native Query
This commit is contained in:
Guilherme Blanco 2012-04-16 07:57:11 -07:00
commit 4debe46d1f
2 changed files with 694 additions and 0 deletions

View File

@ -8,10 +8,13 @@ Index
-----
- :ref:`@Column <annref_column>`
- :ref:`@ColumnResult <annref_column_result>`
- :ref:`@ChangeTrackingPolicy <annref_changetrackingpolicy>`
- :ref:`@DiscriminatorColumn <annref_discriminatorcolumn>`
- :ref:`@DiscriminatorMap <annref_discriminatormap>`
- :ref:`@Entity <annref_entity>`
- :ref:`@EntityResult <annref_entity_result>`
- :ref:`@FieldResult <annref_field_result>`
- :ref:`@GeneratedValue <annref_generatedvalue>`
- :ref:`@HasLifecycleCallbacks <annref_haslifecyclecallbacks>`
- :ref:`@Index <annref_index>`
@ -22,6 +25,7 @@ Index
- :ref:`@ManyToOne <annref_manytoone>`
- :ref:`@ManyToMany <annref_manytomany>`
- :ref:`@MappedSuperclass <annref_mappedsuperclass>`
- :ref:`@NamedNativeQuery <annref_named_native_query>`
- :ref:`@OneToOne <annref_onetoone>`
- :ref:`@OneToMany <annref_onetomany>`
- :ref:`@OrderBy <annref_orderby>`
@ -33,6 +37,7 @@ Index
- :ref:`@PreRemove <annref_preremove>`
- :ref:`@PreUpdate <annref_preupdate>`
- :ref:`@SequenceGenerator <annref_sequencegenerator>`
- :ref:`@SqlResultSetMapping <annref_sql_resultset_mapping>`
- :ref:`@Table <annref_table>`
- :ref:`@UniqueConstraint <annref_uniqueconstraint>`
- :ref:`@Version <annref_version>`
@ -109,6 +114,17 @@ Examples:
*/
protected $height;
.. _annref_column_result:
@ColumnResult
~~~~~~~~~~~~~~
References name of a column in the SELECT clause of a SQL query.
Scalar result types can be included in the query result by specifying this annotation in the metadata.
Required attributes:
- **name**: The name of a column in the SELECT clause of a SQL query
.. _annref_changetrackingpolicy:
@ChangeTrackingPolicy
@ -219,6 +235,39 @@ Example:
//...
}
.. _annref_entity_result:
@EntityResult
~~~~~~~~~~~~~~
References an entity in the SELECT clause of a SQL query.
If this annotation is used, the SQL statement should select all of the columns that are mapped to the entity object.
This should include foreign key columns to related entities.
The results obtained when insufficient data is available are undefined.
Required attributes:
- **entityClass**: The class of the result.
Optional attributes:
- **fields**: Array of @FieldResult, Maps the columns specified in the SELECT list of the query to the properties or fields of the entity class.
- **discriminatorColumn**: Specifies the column name of the column in the SELECT list that is used to determine the type of the entity instance.
.. _annref_field_result:
@FieldResult
~~~~~~~~~~~~~
Is used to map the columns specified in the SELECT list of the query to the properties or fields of the entity class.
Required attributes:
- **name**: Name of the persistent field or property of the class.
Optional attributes:
- **column**: Name of the column in the SELECT clause.
.. _annref_generatedvalue:
@GeneratedValue
@ -597,6 +646,77 @@ Example:
// ... fields and methods
}
.. _annref_named_native_query:
@NamedNativeQuery
~~~~~~~~~~~~~~~~~
Is used to specify a native SQL named query.
The NamedNativeQuery annotation can be applied to an entity or mapped superclass.
Required attributes:
- **name**: The name used to refer to the query with the EntityManager methods that create query objects.
- **query**: The SQL query string.
Optional attributes:
- **resultClass**: The class of the result.
- **sqlResultSetMapping**: The name of a SqlResultSetMapping, as defined in metadata.
Example:
.. code-block:: php
<?php
/**
* @NamedNativeQueries({
* @NamedNativeQuery(
* name = "fetchJoinedAddress",
* resultSetMapping= "mappingJoinedAddress",
* query = "SELECT u.id, u.name, u.status, a.id AS a_id, a.country, a.zip, a.city FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id WHERE u.username = ?"
* ),
* })
* @SqlResultSetMappings({
* @SqlResultSetMapping(
* name = "mappingJoinedAddress",
* entities= {
* @EntityResult(
* entityClass = "__CLASS__",
* fields = {
* @FieldResult(name = "id"),
* @FieldResult(name = "name"),
* @FieldResult(name = "status"),
* @FieldResult(name = "address.zip"),
* @FieldResult(name = "address.city"),
* @FieldResult(name = "address.country"),
* @FieldResult(name = "address.id", column = "a_id"),
* }
* )
* }
* )
* })
*/
class User
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @Column(type="string", length=50, nullable=true) */
public $status;
/** @Column(type="string", length=255, unique=true) */
public $username;
/** @Column(type="string", length=255) */
public $name;
/** @OneToOne(targetEntity="Address") */
public $address;
// ....
}
.. _annref_onetoone:
@OneToOne
@ -801,6 +921,106 @@ Example:
*/
protected $id = null;
.. _annref_sql_resultset_mapping:
@SqlResultSetMapping
~~~~~~~~~~~~~~~~~~~~
The SqlResultSetMapping annotation is used to specify the mapping of the result of a native SQL query.
The SqlResultSetMapping annotation can be applied to an entity or mapped superclass.
Required attributes:
- **name**: The name given to the result set mapping, and used to refer to it in the methods of the Query API.
Optional attributes:
- **resultClass**: Array of @EntityResult, Specifies the result set mapping to entities.
- **columns**: Array of @ColumnResult, Specifies the result set mapping to scalar values.
Example:
.. code-block:: php
<?php
/**
* @NamedNativeQueries({
* @NamedNativeQuery(
* name = "fetchUserPhonenumberCount",
* resultSetMapping= "mappingUserPhonenumberCount",
* query = "SELECT id, name, status, COUNT(phonenumber) AS numphones FROM cms_users INNER JOIN cms_phonenumbers ON id = user_id WHERE username IN (?) GROUP BY id, name, status, username ORDER BY username"
* ),
* @NamedNativeQuery(
* name = "fetchMultipleJoinsEntityResults",
* resultSetMapping= "mappingMultipleJoinsEntityResults",
* query = "SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM cms_users u INNER JOIN cms_addresses a ON u.id = a.user_id INNER JOIN cms_phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username"
* ),
* })
* @SqlResultSetMappings({
* @SqlResultSetMapping(
* name = "mappingUserPhonenumberCount",
* entities= {
* @EntityResult(
* entityClass = "User",
* fields = {
* @FieldResult(name = "id"),
* @FieldResult(name = "name"),
* @FieldResult(name = "status"),
* }
* )
* },
* columns = {
* @ColumnResult("numphones")
* }
* ),
* @SqlResultSetMapping(
* name = "mappingMultipleJoinsEntityResults",
* entities= {
* @EntityResult(
* entityClass = "__CLASS__",
* fields = {
* @FieldResult(name = "id", column="u_id"),
* @FieldResult(name = "name", column="u_name"),
* @FieldResult(name = "status", column="u_status"),
* }
* ),
* @EntityResult(
* entityClass = "Address",
* fields = {
* @FieldResult(name = "id", column="a_id"),
* @FieldResult(name = "zip", column="a_zip"),
* @FieldResult(name = "country", column="a_country"),
* }
* )
* },
* columns = {
* @ColumnResult("numphones")
* }
* )
*})
*/
class User
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @Column(type="string", length=50, nullable=true) */
public $status;
/** @Column(type="string", length=255, unique=true) */
public $username;
/** @Column(type="string", length=255) */
public $name;
/** @OneToMany(targetEntity="Phonenumber") */
public $phonenumbers;
/** @OneToOne(targetEntity="Address") */
public $address;
// ....
}
.. _annref_table:
@Table

View File

@ -394,3 +394,477 @@ For entites with more columns the builder is very convenient to use. It extends
and as such has all the functionality of it as well. Currently the ``ResultSetMappingBuilder`` does not support
entities with inheritance.
Named Native Query
------------------
You can also map a native query using a named native query mapping.
To achieve that, you must describe the SQL resultset structure
using named native query (and sql resultset mappings if is a several resultset mappings).
Like named query, a named native query can be defined at class level or in a XML or YAML file.
A resultSetMapping parameter is defined in @NamedNativeQuery,
it represents the name of a defined @SqlResultSetMapping.
.. configuration-block::
.. code-block:: php
<?php
namespace MyProject\Model;
/**
* @NamedNativeQueries({
* @NamedNativeQuery(
* name = "fetchMultipleJoinsEntityResults",
* resultSetMapping= "mappingMultipleJoinsEntityResults",
* query = "SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM users u INNER JOIN addresses a ON u.id = a.user_id INNER JOIN phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username"
* ),
* })
* @SqlResultSetMappings({
* @SqlResultSetMapping(
* name = "mappingMultipleJoinsEntityResults",
* entities= {
* @EntityResult(
* entityClass = "__CLASS__",
* fields = {
* @FieldResult(name = "id", column="u_id"),
* @FieldResult(name = "name", column="u_name"),
* @FieldResult(name = "status", column="u_status"),
* }
* ),
* @EntityResult(
* entityClass = "Address",
* fields = {
* @FieldResult(name = "id", column="a_id"),
* @FieldResult(name = "zip", column="a_zip"),
* @FieldResult(name = "country", column="a_country"),
* }
* )
* },
* columns = {
* @ColumnResult("numphones")
* }
* )
*})
*/
class User
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @Column(type="string", length=50, nullable=true) */
public $status;
/** @Column(type="string", length=255, unique=true) */
public $username;
/** @Column(type="string", length=255) */
public $name;
/** @OneToMany(targetEntity="Phonenumber") */
public $phonenumbers;
/** @OneToOne(targetEntity="Address") */
public $address;
// ....
}
.. code-block:: xml
<doctrine-mapping>
<entity name="MyProject\Model\User">
<named-native-queries>
<named-native-query name="fetchMultipleJoinsEntityResults" result-set-mapping="mappingMultipleJoinsEntityResults">
<query>SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM users u INNER JOIN addresses a ON u.id = a.user_id INNER JOIN phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username</query>
</named-native-query>
</named-native-queries>
<sql-result-set-mappings>
<sql-result-set-mapping name="mappingMultipleJoinsEntityResults">
<entity-result entity-class="__CLASS__">
<field-result name="id" column="u_id"/>
<field-result name="name" column="u_name"/>
<field-result name="status" column="u_status"/>
</entity-result>
<entity-result entity-class="Address">
<field-result name="id" column="a_id"/>
<field-result name="zip" column="a_zip"/>
<field-result name="country" column="a_country"/>
</entity-result>
<column-result name="numphones"/>
</sql-result-set-mapping>
</sql-result-set-mappings>
</entity>
</doctrine-mapping>
.. code-block:: yaml
MyProject\Model\User:
type: entity
namedNativeQueries:
fetchMultipleJoinsEntityResults:
name: fetchMultipleJoinsEntityResults
resultSetMapping: mappingMultipleJoinsEntityResults
query: SELECT u.id AS u_id, u.name AS u_name, u.status AS u_status, a.id AS a_id, a.zip AS a_zip, a.country AS a_country, COUNT(p.phonenumber) AS numphones FROM users u INNER JOIN addresses a ON u.id = a.user_id INNER JOIN phonenumbers p ON u.id = p.user_id GROUP BY u.id, u.name, u.status, u.username, a.id, a.zip, a.country ORDER BY u.username
sqlResultSetMappings:
mappingMultipleJoinsEntityResults:
name: mappingMultipleJoinsEntityResults
columnResult:
0:
name: numphones
entityResult:
0:
entityClass: __CLASS__
fieldResult:
0:
name: id
column: u_id
1:
name: name
column: u_name
2:
name: status
column: u_status
1:
entityClass: Address
fieldResult:
0:
name: id
column: a_id
1:
name: zip
column: a_zip
2:
name: country
column: a_country
Things to note:
- The resultset mapping declares the entities retrieved by this native query.
- Each field of the entity is bound to an SQL alias (or column name).
- All fields of the entity including the ones of subclasses
and the foreign key columns of related entities have to be present in the SQL query.
- Field definitions are optional provided that they map to the same
column name as the one declared on the class property.
- ``__CLASS__`` is a alias for the mapped class
In the above example,
the ``fetchJoinedAddress`` named query use the joinMapping result set mapping.
This mapping returns 2 entities, User and Address, each property is declared and associated to a column name,
actually the column name retrieved by the query.
Let's now see an implicit declaration of the property / column.
.. configuration-block::
.. code-block:: php
<?php
namespace MyProject\Model;
<?php
/**
* @NamedNativeQueries({
* @NamedNativeQuery(
* name = "findAll",
* resultSetMapping = "mappingFindAll",
* query = "SELECT * FROM addresses"
* ),
* })
* @SqlResultSetMappings({
* @SqlResultSetMapping(
* name = "mappingFindAll",
* entities= {
* @EntityResult(
* entityClass = "Address"
* )
* }
* )
* })
*/
class Address
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @Column() */
public $country;
/** @Column() */
public $zip;
/** @Column()*/
public $city;
// ....
}
.. code-block:: xml
<doctrine-mapping>
<entity name="MyProject\Model\Address">
<named-native-queries>
<named-native-query name="findAll" result-set-mapping="mappingFindAll">
<query>SELECT * FROM addresses</query>
</named-native-query>
</named-native-queries>
<sql-result-set-mappings>
<sql-result-set-mapping name="mappingFindAll">
<entity-result entity-class="Address"/>
</sql-result-set-mapping>
</sql-result-set-mappings>
</entity>
</doctrine-mapping>
.. code-block:: yaml
MyProject\Model\Address:
type: entity
namedNativeQueries:
findAll:
resultSetMapping: mappingFindAll
query: SELECT * FROM addresses
sqlResultSetMappings:
mappingFindAll:
name: mappingFindAll
entityResult:
address:
entityClass: Address
In this example, we only describe the entity member of the result set mapping.
The property / column mappings is done using the entity mapping values.
In this case the model property is bound to the model_txt column.
If the association to a related entity involve a composite primary key,
a @FieldResult element should be used for each foreign key column.
The @FieldResult name is composed of the property name for the relationship,
followed by a dot ("."), followed by the name or the field or property of the primary key.
.. configuration-block::
.. code-block:: php
<?php
namespace MyProject\Model;
<?php
/**
* @NamedNativeQueries({
* @NamedNativeQuery(
* name = "fetchJoinedAddress",
* resultSetMapping= "mappingJoinedAddress",
* query = "SELECT u.id, u.name, u.status, a.id AS a_id, a.country AS a_country, a.zip AS a_zip, a.city AS a_city FROM users u INNER JOIN addresses a ON u.id = a.user_id WHERE u.username = ?"
* ),
* })
* @SqlResultSetMappings({
* @SqlResultSetMapping(
* name = "mappingJoinedAddress",
* entities= {
* @EntityResult(
* entityClass = "__CLASS__",
* fields = {
* @FieldResult(name = "id"),
* @FieldResult(name = "name"),
* @FieldResult(name = "status"),
* @FieldResult(name = "address.id", column = "a_id"),
* @FieldResult(name = "address.zip", column = "a_zip"),
* @FieldResult(name = "address.city", column = "a_city"),
* @FieldResult(name = "address.country", column = "a_country"),
* }
* )
* }
* )
* })
*/
class User
{
/** @Id @Column(type="integer") @GeneratedValue */
public $id;
/** @Column(type="string", length=50, nullable=true) */
public $status;
/** @Column(type="string", length=255, unique=true) */
public $username;
/** @Column(type="string", length=255) */
public $name;
/** @OneToOne(targetEntity="Address") */
public $address;
// ....
}
.. code-block:: xml
<doctrine-mapping>
<entity name="MyProject\Model\User">
<named-native-queries>
<named-native-query name="fetchJoinedAddress" result-set-mapping="mappingJoinedAddress">
<query>SELECT u.id, u.name, u.status, a.id AS a_id, a.country AS a_country, a.zip AS a_zip, a.city AS a_city FROM users u INNER JOIN addresses a ON u.id = a.user_id WHERE u.username = ?</query>
</named-native-query>
</named-native-queries>
<sql-result-set-mappings>
<sql-result-set-mapping name="mappingJoinedAddress">
<entity-result entity-class="__CLASS__">
<field-result name="id"/>
<field-result name="name"/>
<field-result name="status"/>
<field-result name="address.id" column="a_id"/>
<field-result name="address.zip" column="a_zip"/>
<field-result name="address.city" column="a_city"/>
<field-result name="address.country" column="a_country"/>
</entity-result>
</sql-result-set-mapping>
</sql-result-set-mappings>
</entity>
</doctrine-mapping>
.. code-block:: yaml
MyProject\Model\User:
type: entity
namedNativeQueries:
fetchJoinedAddress:
name: fetchJoinedAddress
resultSetMapping: mappingJoinedAddress
query: SELECT u.id, u.name, u.status, a.id AS a_id, a.country AS a_country, a.zip AS a_zip, a.city AS a_city FROM users u INNER JOIN addresses a ON u.id = a.user_id WHERE u.username = ?
sqlResultSetMappings:
mappingJoinedAddress:
entityResult:
0:
entityClass: __CLASS__
fieldResult:
0:
name: id
1:
name: name
2:
name: status
3:
name: address.id
column: a_id
4:
name: address.zip
column: a_zip
5:
name: address.city
column: a_city
6:
name: address.country
column: a_country
If you retrieve a single entity and if you use the default mapping,
you can use the resultClass attribute instead of resultSetMapping:
.. configuration-block::
.. code-block:: php
<?php
namespace MyProject\Model;
<?php
/**
* @NamedNativeQueries({
* @NamedNativeQuery(
* name = "find-by-id",
* resultClass = "Address",
* query = "SELECT * FROM addresses"
* ),
* })
*/
class Address
{
// ....
}
.. code-block:: xml
<doctrine-mapping>
<entity name="MyProject\Model\Address">
<named-native-queries>
<named-native-query name="find-by-id" result-class="Address">
<query>SELECT * FROM addresses WHERE id = ?</query>
</named-native-query>
</named-native-queries>
</entity>
</doctrine-mapping>
.. code-block:: yaml
MyProject\Model\Address:
type: entity
namedNativeQueries:
findAll:
name: findAll
resultClass: Address
query: SELECT * FROM addresses
In some of your native queries, you'll have to return scalar values,
for example when building report queries.
You can map them in the @SqlResultsetMapping through @ColumnResult.
You actually can even mix, entities and scalar returns in the same native query (this is probably not that common though).
.. configuration-block::
.. code-block:: php
<?php
namespace MyProject\Model;
<?php
/**
* @NamedNativeQueries({
* @NamedNativeQuery(
* name = "count",
* resultSetMapping= "mappingCount",
* query = "SELECT COUNT(*) AS count FROM addresses"
* )
* })
* @SqlResultSetMappings({
* @SqlResultSetMapping(
* name = "mappingCount",
* columns = {
* @ColumnResult(
* name = "count"
* )
* }
* )
* })
*/
class Address
{
// ....
}
.. code-block:: xml
<doctrine-mapping>
<entity name="MyProject\Model\Address">
<named-native-query name="count" result-set-mapping="mappingCount">
<query>SELECT COUNT(*) AS count FROM addresses</query>
</named-native-query>
<sql-result-set-mappings>
<sql-result-set-mapping name="mappingCount">
<column-result name="count"/>
</sql-result-set-mapping>
</sql-result-set-mappings>
</entity>
</doctrine-mapping>
.. code-block:: yaml
MyProject\Model\Address:
type: entity
namedNativeQueries:
count:
name: count
resultSetMapping: mappingCount
query: SELECT COUNT(*) AS count FROM addresses
sqlResultSetMappings:
mappingCount:
name: mappingCount
columnResult:
count:
name: count