Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: HasOne overrides nullability of BelongsTo #97

Open
peldax opened this issue Jun 20, 2024 · 5 comments
Open

[Bug]: HasOne overrides nullability of BelongsTo #97

peldax opened this issue Jun 20, 2024 · 5 comments
Labels
status:to be verified Needs to be reproduced and validated. type:bug Bug

Comments

@peldax
Copy link

peldax commented Jun 20, 2024

Describe the bug

Hi,
I am trying to integrate CycleORM into a Symfony application, in order to replace Doctrine, and I encountered a strange behavior with relations.

I will show you the example first.

I trimmed all the other tables and managed to reproduce on following 4 entities:

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

    #[BelongsTo(target: QuestionTextual::class, nullable: true)]
    private ?QuestionTextual $questionTextual = null;

    #[BelongsTo(target: QuestionChoice::class, nullable: true)]
    private ?QuestionChoice $questionChoice = null;

    #[BelongsTo(target: QuestionMultichoice::class, nullable: true)]
    private ?QuestionMultichoice $questionMultichoice = null;
}

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

    #[HasOne(target: Question::class)]
    private Question $question;
}

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

    #[HasOne(target: Question::class)]
    private Question $question;
}

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

    #[HasOne(target: Question::class)]
    private Question $question;
 }

Those entities result in following database schema:

create table question_choices
(
    id int auto_increment
        primary key
);

create table question_multichoices
(
    id int auto_increment
        primary key
);

create table question_textuals
(
    id int auto_increment
        primary key
);

create table questions
(
    id                     int auto_increment
        primary key,
    questionChoice_id      int not null,
    questionTextual_id     int null,
    questionMultichoice_id int null,
    constraint questions_foreign_questionchoice_id_66745e0c2f565
        foreign key (questionChoice_id) references question_choices (id)
            on update cascade on delete cascade,
    constraint questions_foreign_questionmultichoice_id_66745e0c2f6fc
        foreign key (questionMultichoice_id) references question_multichoices (id)
            on update cascade on delete cascade,
    constraint questions_foreign_questiontextual_id_66745e0c2f607
        foreign key (questionTextual_id) references question_textuals (id)
            on update cascade on delete cascade
);

create index questions_index_questionchoice_id_66745e0c2f53b
    on questions (questionChoice_id);

create index questions_index_questionmultichoice_id_66745e0c2f6e5
    on questions (questionMultichoice_id);

create index questions_index_questiontextual_id_66745e0c2f5ef
    on questions (questionTextual_id);

The strange thing this issue is about is the nullability of questionChoice_id column. For some reason the column is declared as NOT NULL, while others are nullable - and all the columns have identical attribute declaration.

In this usecase the question has 3 possible types and the tables include some additional settings. In the base table the relation is nullable, because only one of the 3 columns is filled. However in the extending tables the column is not null, because it must have a base table paired to it.

There might be some sort of misunderstanding of the CycleORM relations on my side, but it seems strange to me that one column has different nullability than the others. When the HasOne attribute is removed from the entitiy, the nullability is corrected.

Is this a regression?

I cannot tell as I am a new user of Cycle ORM.

To Reproduce

Use the default setup and sync a database with entitiy declaration above.

Expected behaviour

The column should be nullable.

Media prove

No response

Database

MySQL

Your environment

  • OS: PopOS
  • PHP version: 8.3.7
  • Package version:
    • annotated: 4.1
    • database: 2.11
    • orm: 2.8
    • schema-builder: 2.8

Additional context

No response

@roxblnfk roxblnfk added type:bug Bug status:to be verified Needs to be reproduced and validated. labels Jun 20, 2024
@roxblnfk
Copy link
Member

Hello. Good catch. Looks like a bug.

@peldax
Copy link
Author

peldax commented Jun 20, 2024

Hi @roxblnfk ,

I tried to dig into the internals but the learning curse seems very steep, as I am not very familiar with the whole system. Would you give me some pointers where to look in order for me to provide a fix? Or is there something else I can do to accelerate the resolution? I am also open to bounty this bug if you had spare time to prioritize things.

Thanks,
VP

@roxblnfk roxblnfk transferred this issue from cycle/schema-builder Jun 20, 2024
@roxblnfk
Copy link
Member

It's nice to hear that.
Perhaps the fixes will be in schema-builder, but I think it's worth starting with tests in the annotated package.

@peldax
Copy link
Author

peldax commented Jun 20, 2024

I tried to work around the issue using JTI and I possibly found another bug, which may be related.

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

    #[BelongsTo(target: OtherEntity::class)]
    protected OtherEntity $otherEntity;
}

#[Entity(database: 'main')]
#[JoinedTable]
class QuestionChoice extends Question
{
}

#[Entity(database: 'main')]
#[JoinedTable]
class QuestionTextual extends Question
{
}

#[Entity(database: 'main')]
#[JoinedTable]
class QuestionMultichoice extends Question
{
 }

By using this attribute setup, all the belongsTo/refersTo relation columns from parent entity (in this case the OtherEntity relation) are added to the parent questions table and also to the all joined tables as well. In my opinion the column should be added only to the parent table.

@roxblnfk
Copy link
Member

In my opinion the column should be added only to the parent table

That's true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:to be verified Needs to be reproduced and validated. type:bug Bug
Projects
Status: Todo
Development

No branches or pull requests

2 participants