2010-02-10 134 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的相关记录和文件 属于该人是 删除。到现在为止还挺好。