2010-02-10 144 views
2

我正在嘗試編寫適當的地圖配置,這將允許我從多對多關係設置中的一側刪除。流利的NHibernate:級聯從一側只從多對多關係中刪除

以下是我的Map和Entity類以及實際程序(僞代碼)和SQL模式的代碼結構。相當簡單直接。

我們有一個人表和一個文件表。然後我們有一個personfile表,因爲一個人可以有很多文件,同樣,一個文件可以分配給很多人。

現在,當我刪除一個人員記錄時,刪除了屬於該人員的personfile和文件中的相關記錄。到現在爲止還挺好。

如果我刪除一個文件(如下面的Program.cs所示),我希望它從personfile和文件中刪除而不是從個人刪除。

然而,隨着我有東西安裝的方式,NHibernate只調用文件表上的刪除,導致一個錯誤。例如。

ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`personfile`, CONSTRAINT `FK_PersonFile2` FOREIGN KEY (`FileID`) REFERENCES `file` (`FileID`)) 

我沒有將Cascade.Delete()添加到FileMap中,但是當我這樣做時,從文件表中刪除也從人員表中刪除。

重申,我最終想要調用刪除(文件),這反過來將從personfile表和文件表中刪除記錄,但不是人表。

我是否應該去獲取人員記錄的路線,然後從person.Files []集合中刪除文件記錄,然後調用SaveOrUpdate()?

考慮這種情況。

首先確保我們在所有表格中都有良好的數據。

現在,在正常情況下,如果你嘗試只刪除文件(這是NHibernate的嘗試基於我的設置做),這是發生了什麼,預計。

mysql> DELETE FROM file WHERE file.FileID = 2; 
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`pe 
rsonfile`, CONSTRAINT `FK_PersonFile2` FOREIGN KEY (`FileID`) REFERENCES `file` (`FileID`)) 

我希望NHibernate做的是這樣的,首先關係表中的記錄被刪除,然後記錄在文件表中。 只要最終結果相同,查詢就不必具體。

mysql> DELETE pf, f 
    -> FROM personfile pf 
    -> LEFT OUTER JOIN file f on pf.FileID = f.FileID 
    -> LEFT OUTER JOIN person p on pf.PersonID = p.PersonID 
    -> WHERE pf.FileID = 2 
    -> ; 
Query OK, 2 rows affected (0.05 sec) 

上述刪除的結果是有效的。

mysql> SELECT f.FileID, p.PersonID, p.Name, f.Filename 
    -> FROM personfile pf 
    -> LEFT OUTER JOIN file f on pf.FileID = f.FileID 
    -> LEFT OUTER JOIN person p on pf.PersonID = p.PersonID 
    -> ; 
+--------+----------+------+------------+ 
| FileID | PersonID | Name | Filename | 
+--------+----------+------+------------+ 
|  1 |  1 | John | Apples.jpg | 
|  3 |  2 | Bob | Grapes.jpg | 
+--------+----------+------+------------+ 
2 rows in set (0.00 sec) 

程序。CS

File file = db.Session.Load<File>(2); 

session.Delete(file); 

transaction.Commit(); 

映射

public class FileMap : ClassMap<File> 
{ 
    public FileMap() 
    { 
    Id(x => x.FileID) 
     .GeneratedBy.Identity(); 
    Map(x => x.Filename) 

    HasManyToMany(x => x.Persons) 
     .Table("PersonFile") 
     .Inverse() 
     .ParentKeyColumn("FileID") 
     .ChildKeyColumn("PersonID"); 
    } 
} 

public class PersonMap : ClassMap<Person> 
{ 
    public PersonMap() 
    { 
    Id(x => x.PersonID) 
     .GeneratedBy.Identity(); 
    Map(x => x.Name) 

    HasManyToMany(x => x.Files) 
     .Table("PersonFile") 
     .Cascade.Delete() 
     .ParentKeyColumn("PersonID") 
     .ChildKeyColumn("FileID"); 
    } 
} 

實體

public class File 
{ 
    public virtual uint FileID { get; set; } 
    public virtual string Filename { get; set; } 

    public virtual IList<Person> Persons { get; set; } 
} 

public class Person 
{ 
    public virtual uint PersonID { get; private set; } 
    public virtual string Name { get; set; } 

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

SQL

CREATE TABLE `file` (
    `FileID` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`FileID`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

CREATE TABLE `person` (
    `PersonID` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`PersonID`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

CREATE TABLE `personfile` (
    `PersonID` int(11) unsigned NOT NULL DEFAULT '0', 
    `FileID` int(11) unsigned NOT NULL DEFAULT '0', 
    PRIMARY KEY (`PersonID`,`FileID`), 
    KEY `FK_PersonFile2` (`FileID`), 
    CONSTRAINT `FK_PersonFile1` FOREIGN KEY (`PersonID`) REFERENCES `person` (`PersonID`), 
    CONSTRAINT `FK_PersonFile2` FOREIGN KEY (`FileID`) REFERENCES `file` (`FileID`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

回答

2

嘗試調用File.Persons.Clear()刪除鏈接的人員,然後再刪除它。

我很好奇這個要求;第二句似乎與它相矛盾,因爲您可以刪除鏈接到不同於您要刪除的人的文件記錄。

我們有一個人表和一個文件表。然後我們有一個人文檔表 ,因爲一個人可以有很多文件,並且同樣可以將一個文件分配給 許多人。

現在,當我刪除一個人的記錄, 在personfile的相關記錄和文件 屬於該人是 刪除。到現在爲止還挺好。