I'm trying to check if a relationship exists or not, in other words, is the column NULL or filled out.
Here I have my QueryBuilder:
$qb->select('v')
->from('Entities\Voucher', 'v')
->leftJoin('Entities\VoucherCopy', 'vc', \Doctrine\ORM\Query\Expr\Join::WITH, 'v.voucherCopy = vc.id')
->where("v.code LIKE :voucherCode")
->andWhere('vc.id IS NULL');
This would be ok if VoucherCopy wasn't Extending "Entities\Codes" - a Single Table Inheritance
VoucherCopy:
class VoucherCopy extends Codes
Codes:
/**
* Entities\DiscountCode
*
* #Table(name="discount_code")
* #Entity()
*
* #InheritanceType("SINGLE_TABLE")
* #DiscriminatorColumn(name="type", type="string")
* #DiscriminatorMap({"D" = "DiscountCode", "VT" = "PortalVoucher", "V" = "VoucherCopy"})
*/
class Codes
The problem is that the executed SQL from this query builder is:
SELECT v0_.*
FROM voucher v0_
LEFT JOIN discount_code d1_ ON (
v0_.discount_code_id = d1_.id
) WHERE (v0_.code LIKE '%DA70511911%' AND d1_.id IS NULL) AND d1_.type IN ('V')
;
Note the AND d1_.type IN ('V'). This is because DQL is automatically adding this because it knows that's the discriminator column for this Entity, but in doing so AND d1_.id IS NULL becomes redundant as I can't check if the relationship fails with the AND d1_.type IN ('V') check.
Is checking if a relationship exists whilst using single table inheritance possible?
I've tried leftJoin to Entities\Code (the parent) directly, but I can't add the discriminator column (type) as a property because you get error: Duplicate definition of column 'type' on entity 'Entities\Codes' in a field or discriminator column mapping.
Related
I've 2 entities: Objetct and Product with a extra ID in each table: officeId
This id is in every table (I cant modify the database )
And 3 tables:
Object
Product
ObjectProduct
I want a manyTomany unidirectional relation.
Entity Object:
class Object
{
/**
* #var Products[]|ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Products")
* #ORM\JoinTable(name="ObjectProduct",
* joinColumns={#ORM\JoinColumn(name="objectId", referencedColumnName="id"),
* #ORM\JoinColumn(name="officeId", referencedColumnName="officeId")},
* inverseJoinColumns={#ORM\JoinColumn(name="productId", referencedColumnName="id"),
* #ORM\JoinColumn(name="officeId", referencedColumnName="officeId")}
* )
*
*/
private $products;
}
My problem is when try to insert, insert the officeId attribute twice:
like:
INSERT INTO ObjectProduct (objectId, officeId, productId, officeId) VALUES (?, ?, ?, ?)
When you use a many to many relation ship (either uni or bi directionnal) it creates a join table. You seems to be aware of this part.
This join table contains tow foreign key that reprensent a composite primary key (to be sure of the unicity). This is automatique
If you wish to change anything (ad an extra ID , extra columns...) then you will need to map it as an entity inside you project and define one to many relation ship instead of many to many
I used to get my data using this command so the first array is for find variable and the second array is for the order.
So I need to order with specific column:name of test(that is an object that has many columns: id/name ) But I dont know how !! when I enter _test.name I get unrecognized field
->findBy(
array('_id' => $id),
array('_test' =>'ASC')
);
class model1
{
private $_idModel1;
/**
*
* #ORM\ManyToOne()
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id1",
* referencedColumnName="id2")
* })
*/
private $_test;
}
You cannot order using a relation with the findBy, but you can do it creating a query builder:
$model1Repository->createQueryBuilder('model1')
->leftJoin('model1._test', 't')
->where('model1._id = :id')
->setParameter('id', $id)
->orderBy('t.name', 'ASC');
The code has not been tested, you should adapt it to your code.
It creates a query builder over the model1 class , then joins it with your ManyToOne relation, filters via _id and then orders the result by the _test relation using the name field.
Aslo you need to declare in the #ManyToOne the target entity (https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/reference/association-mapping.html#many-to-one-unidirectional)
#ManyToOne(targetEntity=TheNameOfTheTestClass)
I am working on a older (laravel 5.6) codebase, this codebase has some models with singular table names (not by my design..). When I setup a new pivot relation between my tables "m_sector" and "m_tasklist" Eloquent automatically assumes that the table name of "m_tasklist" is plural; "m_tasklists". I know this is by Laravel's design, therefor I use a manual override defined in the Tasklist model. After changing the $table property to `protected $table = 'potato'; the changes were detected and implemented in the query..
Error message
"debugMessage": "SQLSTATE[42S02]: Base table or view not found: 1146 Table 'database.m_tasklists' doesn't exist (SQL: select count(*) as aggregate from `m_tasklists` where `id` in (1, 2, 3))"
Tasklist Model
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'm_tasklist';
/**
* A task list belongs to many sectors.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function sector(): BelongsToMany
{
return $this->belongsToMany(Sector::class, 'm_sector_m_tasklist', 'm_tasklist_id', 'm_sector_id');
}
Sector Model
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'm_sector';
/**
* A sector belongs to many task lists.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tasklists(): BelongsToMany
{
return $this->belongsToMany(Tasklist::class, 'm_sector_m_tasklist', 'm_sector_id', 'm_tasklist_id');
}
Picture of PhpMyAdmin table names
Can anyone please help me figure this out, It has been breaking my head for a day now.
If anyone would like to know, the key constraints have formed correctly the migrations work and are set up properly. I can add them if it helps.
The issue wasn't with the model. My usecase had a validation rule which checked whether the item existed in m_tasklists instead of m_tasklist
'rules' => ['exists:m_tasklists,id']
instead of the correct
'rules' => ['exists:m_tasklist,id']
I recommend everyone with a similar problem to run
$ php artisan tinker
$ (new Model)->getTable();
I have: two entities with undirectional M:M association.
class ShareInfo
{
// ...
/**
* #ORM\ManyToMany(targetEntity="Item")
* #ORM\JoinTable(name="share_info_items",
* joinColumns={#ORM\JoinColumn(name="share_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="item_id", referencedColumnName="id")})
*
* #var Item[]
*/
private $items;
}
class Item
{
// ...
// This entity has no association with ShareInfo,
// because M:M is undirectional and defined in ShareInfo entity
}
What I want:
Select data from items table (Item entity), where at least one M:M record between Item and ShareInfo exists.
My suggestion which doesn't work (I've got a semantic error):
$queryBuilder
->select('i')
->from(Item::class, 'i')
->innerJoin(ShareInfo::class, 'shareInfo', 'WITH', 'shareInfo.items = i');
In pure SQL I'd do something like this:
SELECT i.*
FROM items i
INNER JOIN share_info_items shareInfo
ON shareInfo.item_id = i.id
Can't believe there is no DQL analog for this. The only solution I can imagine is to split undirectional M:M association into bi-directional
P.S. This question has no duplicates, I checked well.
The way to achieve this is through a subquery:
$em=$this->getDoctrine()->getManager();
$queryBuilder1=$em->createQueryBuilder();
$queryBuilder1->select(array('DISTINCT i.id'))
->from('AppBundle:ShareInfo', 'share_info')
->innerJoin('share_info.items', 'i');
$queryBuilder=$em->createQueryBuilder();
$queryBuilder->select('i')
->from('AppBundle:items', 'i')
->where($queryBuilder->expr()
->in('i.id',$queryBuilder1->getDql()));
I have an Item entity that has a ManyToOne relationship to a Category entity. I want them to be joined by a field other than Category's id (in this case, a field called id2). My schema is listed below.
class Item {
/**
* #ORM\Id
* #ORM\Column(name = "id", type = "integer")
* #ORM\GeneratedValue(strategy = "AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity = "Category")
* #ORM\JoinColumn(name = "category_id", referencedColumnName = "id2")
*/
protected $category;
}
class Category {
/**
* #ORM\Id
* #ORM\Column(name = "id", type = "integer")
* #ORM\GeneratedValue(strategy = "AUTO")
*/
protected $id;
/**
* #ORM\Column(name = "id2", type = "string", length = "255", unique = "true")
*/
protected $id2;
When I try saving an Item I get this error:
Notice: Undefined index: id2 in vendor/doctrine/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 511
Sure enough, if I change id2 to id in the JoinColumn annotation, everything works fine, but I need the entities to be connected through id2. Is this possible?
Edit
What I want to achieve is impossible according to the official Doctrine 2 docs.
It is not possible to use join columns pointing to non-primary keys.
Doctrine will think these are the primary keys and create lazy-loading
proxies with the data, which can lead to unexpected results. Doctrine
can for performance reasons not validate the correctness of this
settings at runtime but only through the Validate Schema command.
source: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/limitations-and-known-issues.html#join-columns-with-non-primary-keys
I think Doctrine wants these to be primary keys, from the docs:
name: Column name that holds the foreign key identifier for this relation.
Another thing that jumps out at me from your code sample is category.id2 being type string, I would at least expect it to be an integer, but it may also need to be for #JoinColumn to work properly.
You may be able to get away with just #Index on category.id2 and leave it as a string though; worth a shot anyway.
Just to report. I was able to join non-PKs in Many2One (undirectional) relation, BUT my object can't be loaded the normal way. It must be loaded with DQL like:
SELECT d,u FROM DEntity d
JOIN d.userAccount u
this way I stopped getting error: Missing value for primary key id on ....