我正在嘗試編寫適當的地圖配置,這將允許我從多對多關係設置中的一側刪除。流利的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;