I'm trying to rename a table with nativeQuery like this:
$rsm = new ResultSetMapping();
$query = $em->createNativeQuery('RENAME TABLE `'.$oldname.'` TO `'.$newname.'`', $rsm);
$result = $query->getResult();
Strangely the table gets renamed, but the last line throws an error:
Undefined offset: 1
.\vendor\doctrine\dbal\src\Driver\PDO\Exception.php:20
.\vendor\doctrine\dbal\src\Driver\PDO\Result.php:107
.\vendor\doctrine\dbal\src\Driver\PDO\Result.php:38
.\vendor\doctrine\dbal\src\Result.php:59
What am I missing?
You try to execute DDL query like it would be a DML SELECT. There will be no result set as an outcome of such operation
assuming that $em is EntityManager do this
$em->getConnection()->executeQuery($yourQuery);
no ResultSetMapping nor other stuff anywhere.
Please be advised that this is not something I have tested myself nor I am active user of the Doctrine. I am convinced as for the cause, not if the snippet is a valid (googled it out)
Related
I need to find my schema name because i want to delete triggers which i created.
For example the following:
CREATE OR REPLACE TRIGGER TRIGGER_ORDER
BEFORE INSERT ON HOUSE_ORDER
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
WHEN (NEW.ORDER_ID IS NULL)
BEGIN
SELECT SEQ_ORDER_ID.NEXTVAL
INTO :NEW.ORDER_ID FROM DUAL;
END;
/
When i now try to drop the trigger:
DROP TRIGGER TRIGGER_ORDER
I get the following error:
ORA-04080: trigger 'TRIGGER_ORDER' does not exist
I found out that i need to call something like
DROP TRIGGER SCHEMA_NAME.TRIGGER_ORDER
but i have no idea what my schema name is. so how can i find it?
You should use the ALL_TRIGGERS view. There's a column named Table Owner which indicates the schema.
select * from all_triggers
where table_name = 'YOUR_TABLE'
How do I create an insert query in Doctrine that will perform the same function as the following SQL query:
INSERT INTO target (tgt_col1, tgt_col2)
SELECT 'flag' as marker, src_col2 FROM source
WHERE src_col1='mycriteria'
Doctrine documentation says:
If you want to execute DELETE, UPDATE or INSERT statements the Native
SQL API cannot be used and will probably throw errors. Use
EntityManager#getConnection() to access the native database connection
and call the executeUpdate() method for these queries.
Examples
// Get entity manager from your context.
$em = $this->getEntityManager();
/**
* 1. Raw query
*/
$query1 = "
INSERT INTO target (tgt_col1, tgt_col2)
SELECT 'flag' as marker, src_col2 FROM source
WHERE src_col1='mycriteria'
";
$affectedRows1 = $em->getConnection()->executeUpdate($query1);
/**
* 2. Query using class metadata.
*/
$metadata = $em->getClassMetadata(Your\NameSpace\Entity\Target::class);
$tableName = $metadata->getTableName();
$niceTitle = $metadata->getColumnName('niceTitle');
$bigDescription = $metadata->getColumnName('bigDescription');
$metadata2 = $em->getClassMetadata(Your\NameSpace\Entity\Source::class);
$table2Name = $metadata2->getTableName();
$smallDescription = $metadata2->getColumnName('smallDescription');
$query2 = "
INSERT INTO $tableName ($niceTitle, $bigDescription)
SELECT 'hardcoded title', $smallDescription FROM $table2Name
WHERE $niceTitle = 'mycriteria'
";
$affectedRows2 = $em->getConnection()->executeUpdate($query2);
I'm still not convinced it's the right approach you are taking but if you really need an SQL query to be run for whatever reason you can do that in Doctrine with $entityManager->createNativeQuery(); function:
http://doctrine-orm.readthedocs.org/en/latest/reference/native-sql.html
Doctrine isn't a tool for query manipulation. The whole idea is to work on Entity level, not the SQL level (tables, etc). Doctrine's 2 QueryBuilder doesn't even support INSERT operations via DQL.
A small snippet of pseudo code below to illustrate how it can be done in "Doctrine's way":
$qb = $entityManager->createQueryBuilder();
$qb->select('s')
->from('\Foo\Source\Entity', 's')
->where('s.col1 = :col1')
->setParameter('col1', 'mycriteria');
$sourceEntities = $qb->getQuery()->getResult();
foreach($sourceEntities as $sourceEntity) {
$targetEntity = new \Foo\Target\Entity();
$targetEntity->col1 = $sourceEntity->col1;
$targetEntity->col2 = $sourceEntity->col2;
$entityManager->persist($targetEntity);
}
$entityManager->flush();
I'm trying to order the results of my query by whether or not they match my original entity on a property. I could do this easily in mySQL with the following query:
SELECT * FROM table
ORDER BY prop = 'value' DESC;
However, in Doctrine, when I attempt the following:
// $qb is an instance of query builder
$qb->select('e')
->from('Entity', 'e')
->orderBy('e.prop = :value', 'DESC')
->setParameter('value', 'value');
// grab values
I get a Doctrine syntax error, 'end of string'. I looked into creating a custom function, but that seems like overkill. I'm fairly new to Doctrine, is there a better way to do this?
Since Doctrine ORM 2.2, you can use the HIDDEN keyword and select additional fields, in this case with a CASE expression:
SELECT
e,
CASE WHEN e.prop = :value THEN 1 ELSE 0 END AS HIDDEN sortCondition
FROM
Entity e
ORDER BY
sortCondition DESC
As I struggeled a while to figure out how to create that query using php syntax here's what I came up with:
$value = 'my-value';
$qb->select('e')
->from('Entity', 'e')
->addSelect('CASE WHEN e.prop = :value THEN 1 ELSE 0 END AS HIDDEN sortCondition')
->setParameter('value', $value)
->addOrderBy('sortCondition', 'DESC');
I regularly come across a scenario, where I want to query an entity with a specific value:
$query = $em->createQuery('SELECT e FROM Entity e WHERE e.parent = :parent');
$query->setParameter('parent', $parent);
Often, this value can be NULL, but WHERE e.parent = NULL yields no results, forcing me to hack around like this:
if ($parent === null) {
$query = $em->createQuery('SELECT e FROM Entity e WHERE e.parent = IS NULL');
}
else {
$query = $em->createQuery('SELECT e FROM Entity e WHERE e.parent = :parent');
$query->setParameter('parent', $parent);
}
While I understand the rationale behind NULL != NULL in SQL / DQL, the fact is, the consequence is really annoying in this case.
Is there a cleaner way to perform this query, when the parameter can be null?
It's not possible at the moment. (Tried for myself just several ways).
bindValue() with null only works for INSERT/UPDATE value binding.
I think the limitation is in PDO or SQL Syntax itself and not Doctrine.
You can use the QueryBuilder, so you only need to "duplicate" the WHERE part, instead of the whole query: http://doctrine-dbal.readthedocs.org/en/latest/reference/query-builder.html#where-clause
EDIT: It's possible in native SQL: https://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#operator_equal-to
Sadly doctrine does not have that operator: http://doctrine1-formerly-known-as-doctrine.readthedocs.org/en/latest/en/manual/dql-doctrine-query-language.html#operators-and-operator-precedence
You can use query builder:
$em = \Zend_Registry::get('em');
$qb_1 = $em->createQueryBuilder();
$q_1 = $qb_1->select('usr')
->from( '\Entities\user', 'usr' )
->where( 'usr.deleted_at IS NULL' )
->orWhere( 'usr.status='.self::USER_STATUS_ACTIVE )
->andWhere('usr.account_closed_on is null');
$q_1->getQuery()->getResult();
Was just trying to solve the same issue and I actually found a solution for PostgreSQL.
$sql = 'SELECT * FROM company WHERE COALESCE(:company_id, NULL) ISNULL OR id = :company_id;'
$connection->executeQuery($sql, ['company_id' => $id]);
Based on given $id it returns the particular company or all, if null is passed. The problem seems to be that the parser does not know what you are actually going to do with the argument, so by passing it in to COALESCE function it knows that it is passing it into a function, so problem solved.
So if it started working in the "pure" SQL solution, using it inside the DQL should not be a problem. I didn't try that but Doctrine should have COALESCE support so the DQL should be easy to update.
I am building an app in Symfony2, using Doctrine2 with mysql. I would like to use a fulltext search. I can't find much on how to implement this - right now I'm stuck on how to set the table engine to myisam.
It seems that it's not possible to set the table type using annotations. Also, if I did it manually by running an "ALTER TABLE" query, I'm not sure if Doctrine2 will continue to work properly - does it depend on the InnoDB foreign keys?
Is there a better place to ask these questions?
INTRODUCTION
Doctrine2 uses InnoDB which supports Foreign Keys used in Doctrine associations. But as MyISAM does not support this yet, you can not use MyISAM to manage Doctrine Entities.
On the other side, MySQL v5.6, currently in development, will bring the support of InnoDB FTS and so will enable the Full-Text search in InnoDB tables.
SOLUTIONS
So there are two solutions :
Using the MySQL v5.6 at your own risks and hacking a bit Doctrine to implement a MATCH AGAINST method : link in french... (I could translate if needed but there still are bugs and I would not recommend this solution)
As described by quickshifti, creating a MyISAM table with fulltext index just to perform the search on. As Doctrine2 allows native SQL requests and as you can map this request to an entity (details here).
EXAMPLE FOR THE 2nd SOLUTION
Consider the following tables :
table 'user' : InnoDB [id, name, email]
table 'search_user : MyISAM [user_id, name -> FULLTEXT]
Then you just have to write a search request with a JOIN and mapping (in a repository) :
<?php
public function searchUser($string) {
// 1. Mapping
$rsm = new ResultSetMapping();
$rsm->addEntityResult('Acme\DefaultBundle\Entity\User', 'u');
$rsm->addFieldResult('u', 'id', 'id');
$rsm->addFieldResult('u', 'name', 'name');
$rsm->addFieldResult('u', 'email', 'email');
// 2. Native SQL
$sql = 'SELECT u.id, u.name FROM search_user AS s JOIN user AS u ON s.user_id = u.id WHERE MATCH(s.name) AGAINST($string IN BOOLEAN MODE)> 0;
// 3. Run the query
$query = $this->_em->createNativeQuery($sql, $rsm);
// 4. Get the results as Entities !
$results = $query->getResult();
return $results;
}
?>
But the FULLTEXT index needs to stay up-to-date. Instead of using a cron task, you can add triggers (INSERT, UPDATE and DELETE) like this :
CREATE TRIGGER trigger_insert_search_user
AFTER INSERT ON user
FOR EACH ROW
INSERT INTO search_user SET user_id=NEW.id, name=NEW.name;
CREATE TRIGGER trigger_update_search_user
AFTER UPDATE ON user
FOR EACH ROW
UPDATE search_user SET name=name WHERE user_id=OLD.id;
CREATE TRIGGER trigger_delete_search_user
AFTER DELETE ON user
FOR EACH ROW
DELETE FROM search_user WHERE user_id=OLD.id;
So that your search_user table will always get the last changes.
Of course, this is just an example, I wanted to keep it simple, and I know this query could be done with a LIKE.
Doctrine ditched the fulltext Searchable feature from v1 on the move to Doctrine2. You will likely have to roll your own support for a fulltext search in Doctrine2.
I'm considering using migrations to generate the tables themselves, running the search queries w/ the native SQL query option to get sets of ids that refer to tables managed by Doctrine, then using said sets of ids to hydrate records normally through Doctrine.
Will probly cron something periodic to update the fulltext tables.