开发者

Doctrine yaml for a One-To-Many And One-To-One Relationship

I have two objects: File and FileDetail. A File can have many FileDetails, but a FileDetail can only have one File. I can get this to work, but I can't delete anything from the database because of key constraints (I can't delete the File row because FileDetail depends on it, and vice versa). I have the following yaml:

File:开发者_运维知识库
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    ...
    fileDetail_id: integer
  relations:
    ...
    FileDetail:
      local: fileDetail_id
      foreign: id
      cascade: [delete]

FileDetail:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    file_id: integer
    ...
  relations:
    ...
    File:
      local: file_id
      foreign: id
      foreignAlias: Revisions
      cascade: [delete]

Ideally what I would like to happen is when I delete the File row, that all the child FileDetails are deleted as well. It would even be nice if I could just manually delete all the FileDetail rows and then the File row, but because of the key constraints I'm unable to:

1451 - Cannot delete or update a parent row: a foreign key constraint fails (`file`, CONSTRAINT `file_filedetail_id_file_detail_id` FOREIGN KEY (`filedetail_id`) REFERENCES `file_detail` (`id`))

How would I get this type of relationship to work (One-To-Many on one side, but One-To-One on the other). Or should I just treat this as a Many-To-Many on both sides?


With Doctrine, it can often be better to only define the relationship on one side (usually the owning side) and let Doctrine work out the rest. Here, you've got a cascading deletion which looks to be going both ways. Try altering your schema to:

File:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    ...
  relations:
    ...
    Revisions:
      class: FileDetail
      local: id
      foreign: file_id
      type: many
      cascade: [delete]

FileDetail:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    file_id: integer

and leave the cascade on the File side only. That way, when you delete a File, its associated FileDetail records will be deleted as well. I've also changed the alias to Revisions as per your original schema, so you'll be able to do:

$file->Revisions->{some FileDetail field here}

which I think is what you were after. I've removed the filedetail_id field from your File record as if you can have many FileDetail records per file, your File record would not be able to store all the IDs of those records in a single integer field.

And finally, I've added type: many to the owning side, so Doctrine knows that it's a one-to-many relationship from the File side.


A small addition to richsage's answer:

In case you're defining relation on the non-owning side, Doctrine might have problems detecting this setup.

A clear symptom for this is when you get an error message saying that the foreign key column is not found in the referencing table. In these cases you can help out Doctrine providing the "owningSide" attribute in the relation. Taking the above example as a base:

File:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    ...
  relations:
    ...
    Revisions:
      class: FileDetail
      local: id
      foreign: file_id
      type: many
      owningSide: false
      cascade: [delete]


@richsage the only issue I had with your solution, is that for me, in the FileDetail: definition, the file_id: had to have primary: true.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜