您的位置:首页 > 其它

[项目过程中所遇到的各种问题记录]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>集合,同时在实体代码中添加集合对象

配置代码如下:

viewsource

print?

1
<
bag
name
=
"StudentList"
table
=
"Student"
>
2
<
key
column
=
"ID"
/>
3
<
one-to-many
class
=
"Model.Student,Model"
/>
4
</
bag
>
实体代码如下:

viewsource

print?

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
}
2)如果此表存在外键关联,则在映射文件中添加<many-to-one>多对一映射,同时在实体代码中添加实体属性

配置代码如下:

viewsource

print?

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
>
实体代码如下:

viewsource

print?

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对于外键这类数据是采用延迟加载的,而我的查询方式是采用如下代码:

viewsource

print?

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
}
可以看到代码中,我采用using方式将_session在读取完数据后释放了,而此时外键数据,这个时候并没有加载上去,所以,当我需要访问外键数据的时候,NHibernate会再次查询数据库,而此时的_session已经被关闭了,所以就导致了上面的异常。

如果想解决这个问题有2个办法:


1)才用直接加载,在配置的时候为<bag>或<many-to-one>配置上增加lazy=”false”属性,表示不采用延迟加载

2)修改查询代码,不将_session给关闭掉,如下代码:

viewsource

print?

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
}

其实这个问题在李哥(李永京)的NHibernate系列中已经写明了:初探延迟加载机制和初探立即加载机制。

3、复合主键的问题

在实际的数据库表设计中经常会出现复合主键的设计,比如:通过一张关联表来实现2张表之间的多对多关系,如下图:





根据我上面列出的规则,我的配置如下:

viewsource

print?

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
>
实体代码如下:

viewsource

print?

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个字段都只有一个,找了下资料,解决办法还是有,想了解的朋友可以继续查看李哥(李永京)的联合主键(composite-id)这篇文章,不过在李哥的文章中给出的解决方案我觉得有点繁琐,需要将复合主键单独建立一个类,然后重新编写映射关系和实体类。

后来在纠结了很久的情况下,无意中在VS中按空格查看<many-to-one>配置节下可用的属性的时候发现了2个属性insert和update,查了下资料后知道这2个属性是用于控制在新增和更新状态下是否映射,将其都置为false后,代码果然正常执行了,配置如下:

viewsource

print?

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
>
话说,各位看过的朋友如果觉得本文对您还有点用,或者觉得本文还有价值的话,麻烦将鼠标移到【推荐】上,帮我点击下,非常非常的感谢!

项目过程中所遇到的各种问题记录

编辑器篇:

FCKeditor相关知识及各种常见使用问题

FCKeditor自定义上传路径配置

使用FCKeditor生成静态分页HTML

图表篇:

有关MSChart的一些小技巧

asp.net上不错的图表选择—FunsionCharts

ORM篇:

使用NHibernate配置对象实体的一些小问题

有关NHibernate查询封装
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐
章节导航