Wrong ID given in Doctrine2 OneToOne mapping - mysql

I am seriously stack right now with the problem I have occurred with OneToOne mapping.
So let me show what I currently have:
OrderItem entity
/**
* OrderItem
*
* #ORM\Table(name="order_item")
* #ORM\Entity
*/
class OrderItem
{
/**
* #var integer
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
// ... //
/**
* #ORM\OneToOne(targetEntity="UserPricingOption", mappedBy="orderItem")
*/
private $userPricingOption;
/**
* #ORM\ManyToOne(targetEntity="Order", inversedBy="items")
* #ORM\JoinColumn(referencedColumnName="id")
*/
private $order;
// ... //
UserPricingOption entity
/**
* UserPricingOption
*
* #ORM\Table(name="user_pricing_option")
* #ORM\Entity
* #ExclusionPolicy("all")
*/
class UserPricingOption
{
/**
* #var integer
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
// ... //
/**
* #ORM\OneToOne(targetEntity="OrderItem", inversedBy="userPricingOption")
* #ORM\JoinColumn(referencedColumnName="id")
*/
private $orderItem;
// ... //
so generated tables look like this:
order_item table
* `id` 5
user_pricing_option table
* `id` 12
* `order_item_id` 5
So now I am trying to do the following:
echo $orderItem->getId(); // gives 5, `GOOD`
echo $orderItem->getUserPricingOption()->getId(); // gives 5 `BAD` (completely different user_pricing_option row), it should return 12.
I seriously have no idea why is that, please find the raw Doctrine query:
Keep in mind that query contains way more info than the showed examples above
SELECT t0.id AS id_1, t0.guid AS guid_2, t0.created_at AS created_at_3, t0.modified_at AS modified_at_4, t5.id AS id_6, t5.guid AS guid_7, t5.created_at AS created_at_8, t5.modified_at AS modified_at_9, t5.user_id AS user_id_10, t5.order_item_id AS order_item_id_11, t5.pricing_option_id AS pricing_option_id_12, t13.id AS id_14, t13.guid AS guid_15, t13.created_at AS created_at_16, t13.modified_at AS modified_at_17, t13.user_id AS user_id_18, t13.order_item_id AS order_item_id_19, t13.product_variant_id AS product_variant_id_20, t0.order_invoice_id AS order_invoice_id_21, t0.order_id AS order_id_22 FROM order_item t0 LEFT JOIN user_pricing_option t5 ON t5.order_item_id = t0.id LEFT JOIN user_product_variant t13 ON t13.order_item_id = t0.id WHERE t0.order_id = ? [131]
So basically $orderItem->getUserPricingOption()->getId() always returns the same ID as $orderItem->getId();
Anyone possibly see what is going on?

OneToOne bidireccional?
Try to define in joinColumn the name with column to reference id.
/**
* #ORM\OneToOne(targetEntity="OrderItem", inversedBy="userPricingOption")
* #ORM\JoinColumn(name="order_item_id", referencedColumnName="id")
*/
private $orderItem;
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-one-bidirectional

Related

How to make effective index for search

How to make the index on Table for speeding up searching.
I have two tables like these
(I created tables with doctorine from symfony2, but in fetching use plain mysql from python script.)
Now I want to exec this sql many times(changing x value)
select recordDate,closePrice from PriceDay where company_price=x ORDER BY recordDate DESC
So I wan to set the index like indexes={#ORM\Index(name="code_index",columns={"company_price","recordDate"})}) , but I am not sure it is the best solution or not. Pairs of company_price and recordDate are unique. Could you help some ideas??
* #ORM\Table(indexes={#ORM\Index(name="code_index",columns={"company_price","recordDate"})})
PriceDay table
class PriceDay
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\Company")
* #ORM\JoinColumn(name="company_price", referencedColumnName="id")
*/
private $company;
/**
* #ORM\Column(type="float")
*/
private $closePrice = 0;
/**
*
* #ORM\Column(type="date")
*/
private $recordDate;
Company Table
class Company
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string",nullable=false)
*/
private $name;
/**
* #var boolean
* #ORM\Column(name="enabled",type="boolean")
*/
private $enabled = true;

Doctrine does not automatically load joined relation using GROUP BY

I have two Doctrine entity classes: Vertriebsschiene and Filiale:
/**
* Vertriebsschiene
*
* #ORM\Table(name="vertriebsschiene", indexes={
* #ORM\Index(columns={"name"}, flags={"fulltext"})
* }))
* #ORM\Entity(repositoryClass="CRMBundle\Repository\VertriebsschieneRepository")
*/
class Vertriebsschiene
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=100)
*/
private $name;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="Filiale", mappedBy="vertriebsschiene", fetch="EAGER")
*/
private $filialen;
...
}
/**
* Filiale
*
* #ORM\Table(name="filiale")
* #ORM\Entity(repositoryClass="CRMBundle\Repository\FilialeRepository")
*/
class Filiale extends Lieferant
{
/**
* #var Vertriebsschiene
*
* #ORM\ManyToOne(targetEntity="CRMBundle\Entity\Vertriebsschiene", inversedBy="filialen", fetch="EAGER")
*/
private $vertriebsschiene;
...
}
The Vertriebsschine objects have a non-uniqe name. Now I try to display a list of Vertriebsschiene objects with their Filiale objects.
My findAllQuery method looks like this:
/**
* #param User $user
* #return \Doctrine\ORM\Query
*/
public function findAllQuery(User $user){
$qb = $this->createQueryBuilder('v')
->select('v as vertriebsschiene')
->addSelect('COUNT(f) as filial_num')
->leftJoin('v.filialen', 'f')
->groupBy('v.name');
$this->restrictAccess($user, $qb);
return $qb->getQuery();
}
/**
* #param User $user
* #param $qb
*/
protected function restrictAccess(User $user, QueryBuilder &$qb)
{
if ($user->hasRole(RoleVoter::AUSSENDIENST)) {
$qb ->leftJoin('f.vertreter', 'u')
->leftJoin('u.vertretungen', 'vx')
->andWhere($qb->expr()->orX(
'f.vertreter = :userid',
'f.vertreter IS NULL',
$qb->expr()->andX(
'vx.proxy = :userid',
$qb->expr()->between(':currentDate', 'vx.start', 'vx.end')
)
))
->setParameter('userid', $user->getId())
->setParameter('currentDate', new \DateTime(), \Doctrine\DBAL\Types\Type::DATETIME);
}
}
My problem is, that the Vertriebsschiene::$filiale array collection is not automatically loaded, but is loaded for every Vertriebsschiene resulting in many DB connections.
This also has the problem, that the WHERE statement is ignored when the Vertriebsschiene::$filiale is fetched.
The COUNT(f) returns the correct amount of Filiale objects.
I suspect this is an issue with the GROUP BY statement.
I think the problem is that you do not tell doctrine to select filiale fields.
Try to add the filiale alias in your select :
public function findAllQuery(User $user){
$qb = $this->createQueryBuilder('v')
->select('v as vertriebsschiene', 'f')
->addSelect('COUNT(f) as filial_num')
->leftJoin('v.filialen', 'f')
->groupBy('v.name');
$this->restrictAccess($user, $qb);
return $qb->getQuery();
}
If you check your query in the profiler, i think you'll see that doctrine add a LEFT JOIN fialiale f0_ ON v0_.id = f0_.vertriebsschiene_id (or something like this but does not add SELECT ... f0_.id, f0_.xxxx.
So every time you'll call $vertriebsschiene->getFieliale()->getXXX() doctrine will have to execute the corresponding query to get the filiale data.

Building OneToMany and ManyToOne associations beetwen more than three tables via additional table Doctrine 2

Building associations beetwen more than three tables
via additional [EntityTypes] table Doctrine2
I have next schema of database:
//==== some Tables ====
articles (
id
entity_type_id
)
posts (
id
entity_type_id
)
other... (
id
entity_type_id
)
//==== additional table of Types ====
entity_types (
id
)
//==== Comments ====
comments (
id
entity_type_id
entity_id
)
I use Symfony2 with Doctrine2 thereby I've been written next assotiations:
class Article
{
/**
* #ORM\ManyToOne(targetEntity="EntityType", inversedBy="articles", cascade={"persist"})
* #ORM\JoinColumn(name="entity_type_id", referencedColumnName="id")
*/
protected $entityType;
/**
* #ORM\OneToMany(targetEntity="Comment", mappedBy="article")
*/
protected $comments;
}
class Post
{
/**
* #ORM\ManyToOne(targetEntity="EntityType", inversedBy="posts", cascade={"persist"})
* #ORM\JoinColumn(name="entity_type_id", referencedColumnName="id")
*/
protected $entityType;
/**
* #ORM\OneToMany(targetEntity="Comment", mappedBy="post")
*/
protected $comments;
}
...
class EntityType
{
/**
* #ORM\OneToMany(targetEntity="Article", mappedBy="entityType")
*/
protected $articles;
/**
* #ORM\OneToMany(targetEntity="Post", mappedBy="entityType")
*/
protected $posts;
/**
* #ORM\OneToMany(targetEntity="Comment", mappedBy="entityType")
*/
protected $comments;
}
class Comment
{
/**
* #ORM\ManyToOne(targetEntity="EntityType", inversedBy="comments", cascade={"persist"})
* #ORM\JoinColumn(name="entity_type_id", referencedColumnName="id")
*/
protected $entityType;
/**
* #ORM\ManyToOne(targetEntity="Article", inversedBy="comments", cascade={"persist"})
* #ORM\JoinColumn(name="entity_id", referencedColumnName="id")
*/
protected $article;
/**
* #ORM\ManyToOne(targetEntity="Post", inversedBy="comments", cascade={"persist"})
* #ORM\JoinColumn(name="entity_id", referencedColumnName="id")
*/
protected $post;
}
There are no any mistakes in mapping and all operations are available
including commenting articles
but an exception appeared when I'm trying to comment post
need someone to help...

Doctrine query builder - any of joined elements

I have the following entities (simplified):
a work is composed of multiple tasks. Each task has a field storing the time it should be due and a field storing the time it has been completed.
/**
* Work
*
* #ORM\Entity
*/
class Work
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Task", mappedBy="work", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="task_work_id", referencedColumnName="id")
*/
protected $task;
/**
* Constructor
*/
public function __construct()
{
$this->task = new ArrayCollection();
}
}
/**
* Task
*
* #ORM\Entity
*/
class Task
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Work", inversedBy="task")
* #ORM\JoinColumn(name="work_id", referencedColumnName="id")
*/
private $work;
/**
* #var \DateTime
*
* #ORM\Column(name="completed", type="datetime", nullable=true)
*/
private $completed;
/**
* #var \DateTime
*
* #ORM\Column(name="duedate", type="datetime", nullable=true)
*/
private $duedate;
}
I am trying to build a query to retrieve all works that have uncompleted overdue tasks.
I initially thought something like this:
$repository = $this->getEntityManager()
->getRepository('MyBundle:Work');
$query = $repository->createQueryBuilder('v');
$query->leftJoin('v.task', 't');
$query->andWhere(
$query->expr()->isNull('t.completed')
)
->andWhere(
$query->expr()->gte('t.duedate', ':now')
)
;
$query->setParameter('now', new \DateTime(), \Doctrine\DBAL\Types\Type::DATETIME);
However, this retrieves works whose all tasks are overdue (I think).
So I tried with a sub-query:
$repository = $this->getEntityManager()
->getRepository('MyBundle:Work');
$query = $repository->createQueryBuilder('v');
$query2 = $this->getEntityManager()
->createQueryBuilder();
$query2->select('t')
->from('v.task', 't');
$query2->andWhere(
$query->expr()->isNull('t.completed')
)
->andWhere(
$query->expr()->gte('t.duedate', ':now')
)
;
$query2->setParameter('now', new \DateTime(), \Doctrine\DBAL\Types\Type::DATETIME);
$query->andWhere(
$query->expr()->any(
$query2->getDql()
)
);
But I get the following error:
QueryException: [Syntax Error] line 0, col 104: Error: Expected known function, got 'ANY'
Any idea on how I could write the query?
Thank you in advance!
You have not defined a repository for $query2

Can I set up a Symfony2 ORM inheritance relationship using MySQL?

I have one table tech_note and I would like to have 3 tables more tech_note_es, tech_note_en and tech_note_fr (in a future many more tables). And the tech_note can be in the 3 tables at same time.
My idea is attach to tech_note_en and automatically receive attributes from tech_note.
SECOND EDIT:
I would like somthing like that: I search in Tech_note_EN by ID=3 (I recive fields from tech_note_EN with ID=3 and fields tech_note with ID=3.
But if I search in Tech_note_ES BY ID=3 (I recive fields from tech_note_ES with ID=3 and tech_note fields from tech_note with ID=3 (the same fields from above)
The tech_note have a ID=3. Tech_note_EN have ID=3, and Tech_note_ES have ID=3
EDIT WITH NEW CLASSES:
Now I have this error:
Entity 'EVTS\FrontendBundle\Entity\Tech_note_en' has a composite identifier but uses an ID generator other than manually assigning (Identity, Sequence). This is not supported.
TECH_NOTE
abstract class Tech_note {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var datetime $control_date
*
* #ORM\Column(name="control_date", type="datetime")
*/
private $control_date;
/**
* #var string $comment
*
* #ORM\Column(name="comment", type="string")
*/
private $comment;
TECH_NOTE_EN
class Tech_note_en extends Tech_note {
/**
* #var integer $tech_note_id
*
* #ORM\Id
* #ORM\Column(name="tech_note_id", type="integer")
* #ORM\OneToOne(targetEntity="tech_note")
* #ORM\JoinColumn(name="tech_note_id",referencedColumnName="id")
*/
private $tech_note_id;
/**
* #var text $symptom
*
* #ORM\Column(name="symptom", type="text")
*/
private $symptom;
/**
* #var text $cause
*
* #ORM\Column(name="cause", type="text")
*/
private $cause;
/**
* #var string $solution
*
* #ORM\Column(name="solution", type="string")
*/
private $solution;
OLD CLASSES
TECH_NOTE
class Tech_note {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var datetime $control_date
*
* #ORM\Column(name="control_date", type="datetime")
*/
private $control_date;
/**
* #var string $comment
*
* #ORM\Column(name="comment", type="string")
*/
private $comment;
TECH_NOTE_EN
class Tech_note_en
{
/**
* #var integer $tech_note_id
*
* #ORM\Id
* #ORM\Column(name="tech_note_id", type="integer")
* #ORM\OneToOne(targetEntity="tech_note")
* #ORM\JoinColumn(name="tech_note_id",referencedColumnName="id")
*/
private $tech_note_id;
/**
* #var text $symptom
*
* #ORM\Column(name="symptom", type="text")
*/
private $symptom;
/**
* #var text $cause
*
* #ORM\Column(name="cause", type="text")
*/
private $cause;
/**
* #var string $solution
*
* #ORM\Column(name="solution", type="string")
*/
private $solution;
There is an awesome solution to your problem, which is single table inheritance
What this does is basically Have one central table with general fields, and links to other table with specific fields.
In your case I would use this architectural model:
abstract class TechNote (abstract common entity, which contains common fields)
class TechNoteEn extends TechNote (specific entity which inherits common fields and adds specific EN fields)
and so on.
I find this as the best architectural solution for your problem.
That's your ORM's job.
// Assuming $tech_note_en is a Tech_note_en instance
$tech_note_en->getTechNote();
(something like this ^^)