NHibernate经验之谈:Inverse与Cascade
to-many中many的一方进行设置(当然,在many一方,可能是在<set>也可能是在<bag>也可能是在<array>中进行设置),而对于one方,是不进行Inverse设置的。在Hibernate社区,inverse默认值为false。
本节班级(Class类)与学生(Student)、学生(Student)与课程(Course)来进行说明。
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual int Gender { get; set; }
public virtual Class Class { get; set; }
//public virtual int ClassId { get; set; }
public virtual IList<Course> Courses { get; set; }
}
配置(基本部分,不含many-to-one配置。因为各种测试下inverse\cascade值可能不同,所以具体将在各种测试中给出):
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateCascadeInverse.Entities.Student,NHibernateCascadeInverse" lazy="true" table="Student">
<id column="Id" name="Id" type="Int32">
<generator class="native"></generator>
</id>
<property name="Name" column="Name"></property>
<property name="Gender" column="Gender"></property>
<!--<property name="ClassId" column="ClassId"></property>-->
</class>
</hibernate-mapping>
{
public virtual int Id { get; set; }
public virtual string SerialNO { get; set; }
public virtual int DepartmentId { get; set; }
public virtual ISet<Student> Students { get; set; }
}
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateCascadeInverse.Entities.Class,NHibernateCascadeInverse">
<id name="Id" >
<generator class="native"></generator>
</id>
<property column="SerialNO" name="SerialNO" type="string"></property>
<property column="DepartmentId" name="DepartmentId" type="Int32"></property>
</class>
</hibernate-mapping>
测试1:希望在添加班级时,将若干新学生到该班级中。(注意:在此次测试中,删除了Class表与Student表之间的主外键关系。正常为保证数据的完整性还是应建立主外键关系)
class="NHibernateCascadeInverse.Entities.Class,NHibernateCascadeInverse" >
<column name="ClassId" not-null="false" sql-type="int"></column>
</many-to-one>
<key column="ClassId" ></key>
<one-to-many class="NHibernateCascadeInverse.Entities.Student,NHibernateCascadeInverse"/>
</set>
publicvoid ClassAddTest()
{
Class classEntity = new Class
{
SerialNO = "C0302",
DepartmentId = 36,
Students =
new HashedSet<Student> {new Student {Name = "zhangsan"}, new Student {Name = "zhangsan1"}}
};
var repository = new ClassRepository();
repository.Add(classEntity);
}

据插入的Class对象的ClassId将刚插入的Student进行批量更新。
<key column="ClassId" ></key>
<one-to-many class="NHibernateCascadeInverse.Entities.Student,NHibernateCascadeInverse"/>
</set>
class="NHibernateCascadeInverse.Entities.Class,NHibernateCascadeInverse" >
<column name="ClassId" not-null="false" sql-type="int"></column>
</many-to-one>
测试2 结果:

通过以上信息可知:数据被正常保存了,插入数据时,已经为待插入的Student对象构造
好了外键。所以在one-to-many关联中一般通过将many一方(如上例中的Student)作为维护双方关系
的主控方,也就是在one(如上例中的Class)设置inverse="true"
个学生对应多门课程,一门课程也对应许多学生。
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual int TeacherId { get; set; }
public virtual IList<Student> Students { get; set; }
}
Course的映射:(many-to-many部分没有给出,在各种测试中进行不同配置)
<class name="NHibernateCascadeInverse.Entities.Course,NHibernateCascadeInverse" lazy="true" >
<id column="Id" name="Id" type="Int32">
<generator class="native"></generator>
</id>
<property name="Name" column="Name"></property>
<property name="TeacherId" column="teacherID"></property>
</class>
</hibernate-mapping>
<class name="NHibernateCascadeInverse.Entities.Student,NHibernateCascadeInverse" lazy="true" table="Student">
<id column="Id" name="Id" type="Int32">
<generator class="native"></generator>
</id>
<property name="Name" column="Name"></property>
<property name="Gender" column="Gender"></property>
<many-to-one name="Class"
class="NHibernateCascadeInverse.Entities.Class,NHibernateCascadeInverse" >
<column name="ClassId" not-null="false" sql-type="int"></column>
</many-to-one>
<property name="ClassId" column="ClassId"></property>
</class>
</hibernate-mapping>
设置Student为主控方,即Course的Inverse设置为true.Student many-to-many映射
<key foreign-key="FK_CourseInfo_Student" column="StudentId"></key>
<many-to-many class="NHibernateCascadeInverse.Entities.Course,NHibernateCascadeInverse" column="CourseId"></many-to-many>
</bag>
Course many-to-many映射
<key foreign-key="FK_CourseInfo_Course" column="CourseId">
</key>
<many-to-many column="StudentID" class="NHibernateCascadeInverse.Entities.Student,NHibernateCascadeInverse"></many-to-many>
</bag>
publicvoid ManyToMany_Test()
{
var student = new Student { Gender = 1, Name = "testAccount", ClassId = 10 };
var course = new Course { Name = "Computer", TeacherId = 1 };
student.Courses = new List<Course> { course };
course.Students = new List<Student> { student };
StudentRepository studentRepository = new StudentRepository();
CourseRepository courseRepository = new CourseRepository();
//courseRepository.Add(course);
studentRepository.Add(student);
}
测试3 结果:

测试三中,以Student为主控方,保存信息的时候也以Student进行保存。倘若以Course一方进行保存,
数据也能正常写入吗?
测试4: 以受控方(Course )测试保存many-to-many的数据
publicvoid ManyToMany_Test()
{
var student = new Student { Gender = 1, Name = "testAccount", ClassId = 10 };
var course = new Course { Name = "Computer", TeacherId = 1 };
student.Courses = new List<Course> { course };
course.Students = new List<Student> { student };
CourseRepository courseRepository = new CourseRepository();
courseRepository.Add(course);
}
测试4结果:

由测试三、测试四可以看出:两种情况下就Student与Course表的写入顺序不一样,但都能保存正常。所以在many-to-many中,以哪方作为主控方,没有影响。
设置对象关联关系中的级联操作。以上用了cascade="all"。其实它还有其他值:
先通过一个测试简单了解cascade 的作用。
<key column="ClassId" ></key>
<one-to-many class="NHibernateCascadeInverse.Entities.Student,NHibernateCascadeInverse"/>
</set>
Student的配置还如测试一,保持不变。
测试5 结果如下:

还以Class与Student为例进行删除测试。
测试准备:通过测试1,添加一个班级、两条学生信息。
测试:将删除班级中一条学生信息,然后删除班级
测试代码:
public void DeleteClassTest()
{
var repository = new ClassRepository();
Class @class = repository.Get(287);
IEnumerator<Student> students = @class.Students.GetEnumerator();
Student student = null;
if (students.MoveNext())
{
student = students.Current;
}
if (null!=student)
{
@class.Students.Remove(student);
}
repository.Delete(@class); }
测试6 结果:

测试代码同测试六。测试7 结果如下:

由测试六、测试七可知:对于删除与父类之间的关系时,all-delete-orphan会将孤儿删除
(orphan意为:孤儿),而all不会删除,而是将与父关联的外键字段设置为null。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构