[项目过程中所遇到的各种问题记录]ORM篇——使用NHibernate配置对象实体的一些小问题
2010-12-23 12:34
1296 查看
[项目过程中所遇到的各种问题记录]ORM篇——使用NHibernate配置对象实体的一些小问题
继续问题记录,前段时间公司有新的项目所以我想在新的项目里使用NHibernate这类ORM框架来代替原有的代码生成的拼SQL,不过可惜的是最终使用NHibernate还是没成功,最终还是继续使用已有的代码生成方式。NHibernate在去年的这个时候也研究过,可后来也搁浅了,今年的这个时候研究了结果有搁浅了,不知道是不是犯冲?不过还是把遇到的问题记录下来吧,以备后患。
配置实体的一些小问题
下面就开始记录下我碰到的问题吧,其实都是自己没看资料而导致的问题,稍微熟悉NHibernate的朋友都应该知道的。
1、hbm文件的格式检查
这个问题是最弱智的,由于我在手写映射文件的时候没有将NHibernate的XSD文件放到VS相关目录下(X:\ProgramFiles\MicrosoftVisualStudioX.0\Xml\Schemas),而直接根据数据库关系手写了相应的映射文件,结果导致程序一再运行报错(由于NHibernate在运行的时候会将所有的映射文件格式是否正确进行检查),导致不得不反工。
2、延迟加载与直接加载引发的问题
在实际配置映射文件的过程中,我采用的配置方式与Linq2Sql类似,主要的规则就是:
1)如果此表为主键表,其他表中与此表,则在映射文件中添加<bag>集合,同时在实体代码中添加集合对象
配置代码如下:
1 | < bag name = "StudentList" table = "Student" > |
2 | < key column = "ID" /> |
3 | < one-to-many class = "Model.Student,Model" /> |
4 | </ bag > |
01 | private IList<Student>_studentList= new List<Student>(); |
02 |
03 | ///<summary> |
04 | ///子集:ID |
05 | ///</summary> |
06 | public virtual IList<Student>StudentList |
07 | { |
08 | get { return _studentList;} |
09 | set {_studentList=value;} |
10 | } |
配置代码如下:
1 | < many-to-one name = "Class" class = "Model.ClassInfo,Model" > |
2 | < column name = "ClassId" length = "4" sql-type = "int" not-null = "false" /> |
3 | </ many-to-one > |
01 | private ClassInfo_class; |
02 |
03 | ///<summary> |
04 | ///外键:ClassId |
05 | ///</summary> |
06 | public virtual ClassInfoClass |
07 | { |
08 | get { return _class;} |
09 | set {_class=value;} |
10 | } |
如果是正常访问类本身属性是没什么问题,但是如果访问上面配置外键Class属性或者StudentList集合属性就会出现下面的异常:
其原因就是延迟加载导致,由于默认情况下NHibernate对于外键这类数据是采用延迟加载的,而我的查询方式是采用如下代码:
1 | public virtual IList<T>GetList() |
2 | { |
3 | using (_session=NHibernateHelper.GetCurrentSession()) |
4 | { |
5 | IList<T>list=(fromitem in _session.Query<T>() |
6 | selectitem).ToList<T>(); |
7 | return list; |
8 | } |
9 | } |
如果想解决这个问题有2个办法:
1)才用直接加载,在配置的时候为<bag>或<many-to-one>配置上增加lazy=”false”属性,表示不采用延迟加载
2)修改查询代码,不将_session给关闭掉,如下代码:
1 | public virtual IList<T>GetList() |
2 | { |
3 | _session=NHibernateHelper.GetCurrentSession(); |
4 |
5 | IList<T>list=(fromitem in _session.Query<T>() |
6 | selectitem).ToList<T>(); |
7 | return list; |
8 |
9 | } |
其实这个问题在
3、复合主键的问题
在实际的数据库表设计中经常会出现复合主键的设计,比如:通过一张关联表来实现2张表之间的多对多关系,如下图:
根据我上面列出的规则,我的配置如下:
01 | < hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" > |
02 | < class name = "Model.SubjectAndStudent,Model" table = "SubjectAndStudent" > |
03 |
04 | < composite-id > |
05 | < key-property name = "SubjectId" type = "int" > |
06 | < column name = "SubjectId" length = "4" sql-type = "int" not-null = "false" /> |
07 | </ key-property > |
08 | < key-property name = "StudentId" type = "int" > |
09 | < column name = "StudentId" length = "4" sql-type = "int" not-null = "false" /> |
10 | </ key-property > |
11 | </ composite-id > |
12 | < many-to-one name = "Subject" class = "Model.Subject,Model" > |
13 | < column name = "SubjectId" length = "4" sql-type = "int" not-null = "false" /> |
14 | </ many-to-one > |
15 | < many-to-one name = "Student" class = "Model.Student,Model" > |
16 | < column name = "StudentId" length = "4" sql-type = "int" not-null = "false" /> |
17 | </ many-to-one > |
18 | </ class > |
19 | </ hibernate-mapping > |
01 | public class SubjectAndStudent |
02 | { |
03 |
04 | public virtual int SubjectId{ get ; set ;} |
05 |
06 | public virtual int StudentId{ get ; set ;} |
07 |
08 | public virtual SubjectSubject{ get ; set ;} |
09 |
10 | public virtual StudentStudent{ get ; set ;} |
11 |
12 | #regionoverride |
13 | public override bool Equals( object obj) |
14 | { |
15 | return base .Equals(obj); |
16 | } |
17 | public override int GetHashCode() |
18 | { |
19 | return base .GetHashCode(); |
20 | } |
21 | #endregion |
22 |
23 | } |
这边需要注意的是,采用复合主键映射,在编写实体类的时候,需要重载Equals和GetHashCode方法,否则会报错。
正常来看,这个映射和实体代码的编写没什么问题,但是在实际的新增运行过程中出现了这个问题:
仔细查看了下映射文件才发现问题所在,就是在具体的配置映射关系的时候将SubjectId和StudentId配置了2次,而实际在表中,这2个字段都只有一个,找了下资料,解决办法还是有,想了解的朋友可以继续查看
后来在纠结了很久的情况下,无意中在VS中按空格查看<many-to-one>配置节下可用的属性的时候发现了2个属性insert和update,查了下资料后知道这2个属性是用于控制在新增和更新状态下是否映射,将其都置为false后,代码果然正常执行了,配置如下:
1 | < many-to-one name = "Subject" class = "Model.Subject,Model" insert = "false" update = "false" > |
2 | < column name = "SubjectId" length = "4" sql-type = "int" not-null = "false" /> |
3 | </ many-to-one > |
4 | < many-to-one name = "Student" class = "Model.Student,Model" insert = "false" update = "false" > |
5 | < column name = "StudentId" length = "4" sql-type = "int" not-null = "false" /> |
6 | </ many-to-one > |
项目过程中所遇到的各种问题记录
编辑器篇:
图表篇:
ORM篇: