1

I have got two entities: Document and File connected in Many-To-Many relationship. I want them to behave as follows:

  1. Document has many files.
  2. Files can belong to many documents at the same time.
  3. When I delete document, each file should be deleted as well, unless it belongs to another document.
  4. When I delete some file from document, it should be deleted, unless it belongs to another document.

Entities:

public class Document
{
    public virtual int DocumentId { get; set; }

    public virtual ICollection<File> Files { get; set; }
}

public class File
{
    public virtual int FileId { get; set; }

    public virtual ICollection<Document> DocumentsAttachedIn { get; set; }
}

Mappings:

public DocumentMap()
{
    SelectBeforeUpdate();
    DynamicUpdate();
    Id(x => x.DocumentId).Column("DocumentId");
    HasManyToMany(x => x.Files)
        .AsSet()
        .Cascade.AllDeleteOrphan()
        .Table("DocumentFile")
        .ParentKeyColumn("DocumentId")
        .ChildKeyColumn("FileId");
}

public FilesMap()
{
    SelectBeforeUpdate();
    DynamicUpdate();

    Id(f => f.FileId).Column("FileId");
    HasManyToMany(f => f.DocumentsAttachedIn)
        .Inverse()
        .Table("DocumentFile")
        .ChildKeyColumn("DocumentId")
        .ParentKeyColumn("FileId");
}

I have saved two instances of Document, with the same file inside. When I try to delete a file from Document.Files, or when I delete whole Document, I get following exception:

could not delete: [MyNameSpace.Files.Business.File#1][SQL: DELETE FROM File WHERE FileId = ?]

Inner Exception:

Cannot delete or update a parent row: a foreign key constraint fails (my_base.documentfile, CONSTRAINT FKDB8FFE6221523AA6 FOREIGN KEY (FileId) REFERENCES file (FileId))

Indeed, I have such constraint and I want to keep it. The question is why NHibernate tries to delete it, when I explicitly told in mappings: Cascade.AllDeleteOrphan()

Kuba Matjanowski
  • 350
  • 3
  • 14

1 Answers1

1

The solution of these:

  1. When I delete document, each file should be deleted as well, unless it belongs to another document.
  2. When I delete some file from document, it should be deleted, unless it belongs to another document.

is: solve it yourself on the business layer. NHibernate cascade will not work here. It is there to do a cascade in full range (if turned on) or no (if turned off). Nothing between

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • So the problem was in my understanding of `DeleteOrphans`. I assumed, the orphan is the row that don't have any parents, while in real it's a row whose any parent is currently being deleted. To make it working I need to change`Cascade.AllDeleteOrphan()` to`Cascade.All()` and implement removing children not owned by anyone in C# code. Am I right? – Kuba Matjanowski Feb 17 '16 at 08:58
  • 1
    I would say, that in this case, you should not use cascade at all. The pairing table will be cascaded by default (that is internal NHibernate domain) .. but the other end should be managed just by the application... hope this helps a bit – Radim Köhler Feb 17 '16 at 10:49