cycle / orm

PHP DataMapper, ORM
https://cycle-orm.dev
MIT License
1.21k stars 70 forks source link

🐛 Self transation cannot be resolved. #489

Open peldax opened 1 week ago

peldax commented 1 week ago

No duplicates 🥲.

What happened?

Hi,

I am getting a following error when persisting a self referencing entitiy, such as following:

#[Entity(database: 'main')]
class Catalogue
{
    #[Column(type: 'primary')]
    private int $id;

    #[RefersTo(target: self::class, nullable: true)]
    private ?self $catalogue = null;

    #[HasMany(target: self::class)]
    private array $catalogues = [];
}

Error message:

Cycle\ORM\Exception\TransactionException: Transaction can't be finished. Some relations can't be resolved:
Create new `catalogue`
 - catalogue.catalogues:catalogue (Cycle\ORM\Relation\ShadowBelongsTo)

It seems that the ORM is having trouble understanding the selfReferencing relation.

Version

- ORM 2.8
- PHP 8.3.7
roxblnfk commented 1 week ago

There is test for many-to-many relation https://github.com/cycle/orm/tree/many-to-many-self-cyclic

peldax commented 1 week ago

Hi @roxblnfk,

I found that when the HasMany catalogues relation is marked as nullable, the persisting happens correctly.

Does it make sense that the HasMany relation must explicitly know whether the targeting entity allows null or not? In my opinion the BelongsTo/RefersTo relations should have the final (and possibly the only) word about its nullability - this is the relevant column after all.

roxblnfk commented 1 week ago

Hi

Does it make sense that the HasMany relation must explicitly know whether the targeting entity allows null or not? In my opinion the BelongsTo/RefersTo relations should have the final (and possibly the only) word about its nullability - this is the relevant column after all.

At the ORM level, we declare relationships, not table columns. For example, there can be a situation: Parent#hasOne(Child, nullable=true) + Child::belongsTo(Parent, nullable=false). Here, the Parent may not have a Child because the relationship is optional in this direction. However, if a Child appears in the database, it will always have a Parent. HasOne does not affect the nullable property of the parent_id column.

However, it seems odd that the nullable property in HasMany affects anything. Could you add a test case so that we can poke around with it?

peldax commented 1 week ago

Hi, Thanks for the reply. I understand the usecase with HasOne, but this does not apply on the HasMany relation - there either exists some related entities or not. I think that the nullability of a target is irrelevant on the HasMany relation, please correct me if I am wrong.

Either way, it is great that it is not an intended behaviour and it should not change anything in the persisting process. I will dig deeper and try to provide a solution. I will start with the testcase.