Doctrine2: OneToMany on mapped superclass - doctrine-orm

My DB structure is as follows:
work:
CTI table Work
MappedSuperclass table AbstractImageWork which extends Work
final table PhotoWork which extends AbstractImageWork
comment:
MappedSuperclass table Comment
final table WorkComment which extends Comment
WorkComment has a ManyToOne relation to Work:
#ManyToOne(targetEntity="Work", inversedBy="comments")
Work has a OneToMany relation to WorkComment:
#OneToMany(targetEntity="WorkComment", mappedBy="work")
The problem is that Doctrine gives me this error while updating the schema:
[Doctrine\ORM\Mapping\MappingException]
It is illegal to put an inverse side one-to-many or many-to-many association on
mapped superclass 'Acme\...\AbstractImageWork#comments'.
I guess this has something to do with the MappedSuperclass AbstractImageWork stuck in the middle between Work and PhotoWork, but I didn't actually put this relation on the MappedSuperclass, but on the CTI table.. so why will Doctrine behave like this?
Any ideas?

In some cases, when you have such error when inherit from the class that is tagged as #ORM\MappedSuperclass, try to change your properties access level from private to protected

A mapped superclass cannot be an entity, it is not query-able and persistent relationships defined by a mapped superclass must be unidirectional (with an owning side only). This means that One-To-Many associations are not possible on a mapped superclass at all. Furthermore Many-To-Many associations are only possible if the mapped superclass is only used in exactly one entity at the moment. For further support of inheritance, the single or joined table inheritance features have to be used.
Check it out here: https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/inheritance-mapping.html

In others cases happens when you declare #ORM\Entity in an abstract superior class instead of #ORM\MappedSuperclass

Related

Doctrine ORM, Coalesce in JoinColumn

Do we at this moment have a way to use coalesce in the join column for relations?
For example a car has many parts. A car can have a relation to itself. I want to make demo cars, which refer to another car (the original car). But i do not want to copy all the parts of the car. So i would like to join using Coalesce. join part.car_id = coalesce(car.car_id, car.id). So we would use the coalesce to first check if the car as a car_id, referring to the original car, if so, its a demo car and we use the car id of the original car. If not than use the car's own id. For example when calling the original car.
If this would not be possible using the Annotations. Would it be possible in a different way?
It is not possible to define conditions on doctrine association. Association is always defined between concrete entities and fields.
It also doesn't work with constrains in relational databases.
I think you should use different design to achieve it. I would recommend to introduce new entity Model and associate parts to this entity and then have a Car which is also associated to the Model.

Which object should hold the many-to-many relationship in Django?

I'm just learning Django and have a quick question: I see that when creating a model you can define a many-to-many relationship between two objects. While you assign this relationship to one of the objects, Django actually creates a third table to resolve this M:N relationship. Given this, does it matter which object holds the many-to-many field or can it appear on either of the two, related objects? (coming from a relational DB background, I've got to say that the concept of assigning the M:N to one table feels a bit odd - I'm still not over the idea of not starting with an ER diagram)
No, it doesn't matter. It can go on either of the two.

Prevent Django from joining superclass' table

Having a non-abstract parent class:
class Animal(models.Model)
and two subclasses:
class Cow(Animal)
class Dog(Animal)
and calling
Dog.objects.order_by('name')
queries the database and returns joined records:
SELECT ... FROM dog
INNER JOIN animal ON (dog.animal_ptr_id = animal.id)
ORDER BY dog.name ASC
However in my case "dog" is not a table, but a complicated view defined in the database. The view already contains all needed fields from "animal" including the animal id accessible by animal_ptr__id.
How can I prevent django from making the INNER JOIN which drastically slows down the query?
I don't really understand why you think dog is not a table in this case, since you are not using abstract base class. It is therefore multi-table inheritance and each subclass does have a table.
To the best of my knowledge the best way to avoid INNER JOIN for multi-table inheritance is to use abstract base class by setting abstract = True in class Meta. It seems like this what you should be doing, but..
It is possible, however, to use raw SQL queries if you insist on using multi-table inheritance. Something like this might work:
Dog.objects.raw('SELECT ... FROM myapp_dog ORDER BY dog.name ASC')
Though dog table alone will not contain the properties it inherited from the base class Animal. To get those inherited properties, I think a JOIN is unavoidable unless I missed something obvious..
However in my case "dog" is not a table, but a complicated view
defined in the database.
You need to set managed = False for Dog; otherwise you aren't using your view but an intermediary table called app_dog (where app is your app name).
This prevents django from creating a table but to use one internally defined (in your case, the view). Make sure you also specify a key, and specify the table name.

How do I express a Django ManyToMany relationship?

I'm hitting a wall here and I know this is a simple question, but I was unable to find it here.
In an ER diagram, what would the relationship be between two objects that have a ManyToMany relationship, in terms of the intermediary table?
Example:
item ---- item_facts ---- fact
I feel like it should be one to one but I'm not completely sure.
user --many2many-- group
user 1----n user_group n---1 group
In django documentation it states that
A many-to-many relationship. Requires a positional argument: the class to which the model is related. This works exactly the same as it does for ForeignKey, including all the options regarding recursive and lazy relationships.
Behind the scenes, Django creates an intermediary join table to represent the many-to-many relationship. By default, this table name is generated using the name of the many-to-many field and the model that contains it. Since some databases don't support table names above a certain length, these table names will be automatically truncated to 64 characters and a uniqueness hash will be used. This means you might see table names like author_books_9cdf4; this is perfectly normal. You can manually provide the name of the join table using the db_table option.
And ForeignKey definition is like:
A many-to-one relationship. Requires a positional argument: the class to which the model is related.
So,ManyToMany relations created by django are creating intermedıary tables that are 1 to N.
Not sure what the question is here. You say that the two objects have a many-to-many relationship.
If two objects (entitied, tables) have a many-to-many relationship, whether you include the intermediate table in the diagram or not, is irrelevant. They still have a many-to-many relationship.

Doctrine2: Uni-directional #OneToMany with foreign key?

I have a "Product" entity with many "Video" entities, and I only need a unidirectional #OneToMany with foreign key (one product, many videos). My Product-side "key" is not primary or unique, which is why I need it to be unidirectional (eg, "select * from videos where product_family = 2143")
I'm using Doctrine 2.1
Is there yet a way to do uni-directional #OneToMany with only a foreign-key in Doctrine 2.1? If not, soon?
UPDATE: I found a relevant quote from Roman Borschel on May 2010:
"this would need quite some special-case handling in many places. In the light that there are 2 reasonably good alternatives (mapping through a jointable or simply making the association bidirectional) we do not consider this something that really needs to be done."
Has this opinion by the Doctrine2 team changed?
OneToMany by design has the related ID on the "Many" side of the relationship. So to make the child table relate to the parent without an additional field in a join table is not possible.