Inserting Data (append)

append is ObjectQuel's bulk, set-based insert statement — QUEL's insert verb, run directly against the database through the same EntityManager::executeQuery() entry point as retrieve and the DDL statements on Creating, Altering & Destroying Tables & Indexes. It bypasses the identity map and change tracking entirely. If you need entity lifecycle behavior — cascades, events, per-object optimistic-lock exceptions — use persist()/flush() instead. See also replace, delete, and upsert.

explanation

Inserting Data with append

Assign each property a value using attr = value pairs:

$entityManager->executeQuery("
    range of u is App\\Entity\\UserEntity
    append to u (username = :username, password = :password, banned = false)
", ['username' => 'alice', 'password' => 'secret']);

Auto-generated primary keys (identity, sequence, UUID) are generated automatically, as with persist(); provide one only to override it. Other columns must be supplied unless nullable or defined with @Orm\Column(default=...). Omitted nullable columns are excluded from the INSERT, letting the database apply DEFAULT or NULL. Columns with default=... use the annotation's value; PHP property defaults have no effect. Any other unassigned column is rejected before the statement reaches the database.

That validation runs against the range's entity metadata. Every range in ObjectQuel resolves to a mapped entity — range of x is Name is a parse-time error when Name doesn't match a known entity class.

Multi-Row Append

Comma-separated value tuples insert several rows in one statement. Every row must assign the same set of properties:

$entityManager->executeQuery('
    range of u is App\Entities\UserEntity
    append to u
        (username = "carol", password = "pw1", banned = false),
        (username = "dave",  password = "pw2", banned = false)
');
getGeneratedId() returns null for a multi-row append — which row's identity value it would even refer to is ambiguous, so it's left unset rather than guessed at.

Insert-from-Select

A bare column list (no =) followed by a retrieve copies rows from another range instead of literal values. The presence or absence of = in the parenthesized list is the only thing that distinguishes this form from the literal-values form above:

$entityManager->executeQuery('
    range of dst is App\Entities\ArchivedOrderEntity
    range of src is App\Entities\OrderEntity
    append to dst (name, total) retrieve (src.name, src.total) where src.closed = true
');

Working with the Result

append returns a QuelResult with no fetchable rows — getAffectedRows() and getGeneratedId() are the accessors that matter here, in place of iterating the result the way a retrieve result is iterated:

$result = $entityManager->executeQuery($query, $parameters);

$affected = $result->getAffectedRows();
$newId    = $result->getGeneratedId(); // null unless a single row was inserted with a generated PK

getGeneratedId() is populated only for single-row literal append. It is null for multi-row append and insert-from-select. Upsert statements follow a related but slightly different rule — see "Working with the Result" on that page.

There is no RETURNING/output-clause support — the generated primary key comes back via getGeneratedId(), not a SQL-level RETURNING/OUTPUT clause. MySQL has no native equivalent to RETURNING at all.