阿不

不抛弃,不放弃

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  158 随笔 :: 0 文章 :: 2073 评论 :: 66 Trackbacks

       在用Ado.Net进行数据库访问操作中,最麻烦的就是准备DbCommand必须为它添加DbParameter,特别是当要传的参数特别多的情况下,数据访问层的很多代码都是花在这里。iBatisParameterMap配置就是针对这个问题所提出的一种解决方案,基于xml的配置,把字段名和对象的属性对应起来,通过运行时的一些工作,自动为DbCommand提供它所需的参数集合。从而避免了我们直接写很多重复代码。

Employees_ParameterMap.xml配置文件中:

<select id="Employees_SelectWithParameterClass" parameterClass="Employee" resultClass="Employee" listClass="ArrayList">

    SELECT EmployeeID,LastName,FirstName FROM Employees WHERE EmployeeID = #EmployeeID# OR LastName = #LastName#

</select>

使用的是内联参数映射的方式,语句的在执行查询时只需为它提供Employee类型的对象,它就会自动去读自己需要的EmployeeIDLastName属性的值,返回查询结果。在执行时它所执行的语句如下:

[SELECT EmployeeID,LastName,FirstName FROM Employees WHERE EmployeeID =  @param0  OR LastName =  @param1]

所需的参数的提供方式如下:

[@param0=[EmployeeID,12], @param1=[LastName,8bbb7bfb-c]]

并且,在iBatis中还会指出各个参数的类型:

[@param0=[Int32, System.Int32], @param1=[String, System.String]]

对于下面这个配置:

<select id="Employees_SelectWithParameterMap1" parameterMap="Employee_SelectParameterMap" resultClass="Employee" listClass="ArrayList">

        SELECT EmployeeID,LastName,FirstName FROM Employees WHERE EmployeeID = #EmployeeID# OR LastName = #LastName# OR Country = #Country#

    </select>

它所使用的ParameterMap配置如下:

    <parameterMap class="Employee" id="Employee_SelectParameterMap">

        <parameter column="EmployeeID" property="EmployeeID" dbType="int" type="int" direction="Input"/>

        <parameter column="LastName" property="LastName" dbType="nvarchar" type="string" direction="Input"/>

        <parameter column="Country" property="Country" dbType="nvarchar" type="string" direction="Input"/>

    </parameterMap>

在每一个Parameter映射元素可以指定每个属性对应的列,它的类型和对应的数据库的类型,还可以指定当它为空值时的默认值,具体可以参看官方文档。但是可以看到,我们期待它能和内联参数一样的使用方法,如上配置的那样。可是行不行呢?从程序的执行结果来看,是不可以的。由于之前在配置SQL语句的时候基本都是使用内联参数没有特别注意到这点。在使用Parameter Map的时候是不能用#property#的形式显示地指定要使用的属性参数,只能通过“?”,顺序替代每一个parameter元素,如下:

<select id="Employees_SelectWithParameterMap2" parameterMap="Employee_SelectParameterMap" resultClass="Employee" listClass="ArrayList">

            SELECT EmployeeID,LastName,FirstName FROM Employees WHERE EmployeeID = ? OR LastName = ? OR Country = ?

    </select>

可以看到,由于没有明显地指出EmployeeID对应哪个属性,那如果把上面的parameter元素调换一下,那么EmployeeID所对应的参数值就发生变化了。同时,也是这个原因,通过这种方式的参数映射,就无法重复利用每个参数了。如果仔细观察会发现,既然都指定了column属性了,那它为什么不会自动去配置呢?其实在这边column属性是不起作用的,它只会作用在执行存储过程的时候。也就是说上面的Parameter元素中的column属性不是必须的。下面是一个存储过程的例子:

<procedure id="Employee_InsertWithProcedure" parameterMap="Employee_InsertParameterMap2" resultClass="int">

    InsertEmployee

</procedure>

    InsertEmployee接受两个参数@LastName@FirstName。我给它提供的映射参数如下:

<parameterMap class="Employee" id="Employee_InsertParameterMap2">          

    <parameter column="LastName" property="LastName" dbType="nvarchar" type="string" direction="Input"/>

    <parameter column="FirstName" property="FirstName" dbType="nvarchar" type="string" direction="Input"/>

</parameterMap>

    上面这样的配置的结果是(其中逗号后面的是值):

[@LastName=[LastName,9a8bc059-3], @FirstName=[FirstName,46887db0-2]]

但是当我把他们的位置调换了一下。它的结果如下:

[@LastName=[ FirstName,9a8bc059-3], @FirstName=[LastName,46887db0-2]]

也就是对储存过程也是一样的,参数映射关系仍然与parameter元素的顺序息息相关的。Column属性仍然没有显示出它的作用。所以使用ParameterMap还有是有一定的局限性的。但是对存储过程来说,就必须使用这样的方式,因为它只支持ParameterMap为它提供参数,而不支持内联参数。

最后总结列出几点ParameterMap需要特别注意的几个细节:

1.在配置ParameterMap的时候,如果传入的参数对像是元数据类型(int,string etc),那么在配置Parameter元素的时候,property的属性名使用value。通过这种情况主要使用在为存储指定参数的情况下。

2.如果ParameterMap中配置的parameter元素不包含在传入参数对象中(属性或IDictionary对象的一个key,value项),将会产生异常,而不管在statement中有没有用到。

3.在使用parameterMapextends属性时,它将会继承extends值对应的parameterMap配置,并且会继承它的所有的参数映射,并且顺序是从继承的那配置为基准开始计算。这个在需要用到extends属性的时候要特别注意。

4.在为存储过程传参过程要特别注意,参数映射与存储过程的参数之间的顺序对应要正确。而且必须为提供与存储过程足够的参数(parameter配置足够多),即使存储过程的部分参数已经有默认值了。否则将抛出System.ArgumentOutOfRangeException异常。

5.正常情况下,应该尽量使用内联参数。

源代码下载

阿不 http://hjf1223.cnblogs.com
posted on 2006-05-06 08:43 阿不 阅读(2976) 评论(30)  编辑 收藏 所属分类: Ibatisnet

评论

#1楼  2006-09-04 15:58 hpy223 [未注册用户]
请问 ibatisnet 怎么获取执行存储过程后的output 参数的值?
  回复  引用    

#2楼 [楼主] 2006-09-04 18:02 阿不      
你可以通过传入参数对象的RsCounts属性就可以取得输出值了,谢谢。
  回复  引用  查看    

#3楼  2006-09-05 11:43 hpy223 [未注册用户]
我的QQ:99282890
  回复  引用    

#4楼  2006-09-05 11:43 hpy223 [未注册用户]
您好!
能不能具体说一下,或者请留下您的QQ或者MSN,和您详谈!
  回复  引用    

#5楼 [楼主] 2006-09-05 11:46 阿不      
@hpy223
你可以给我留言,我会给你回邮件的。
  回复  引用  查看    

#6楼  2006-09-05 12:01 hpy223 [未注册用户]
想不到这么快就给回邮件了,谢谢了,我的Email:hpy223@napu.com.cn
谢谢了!
  回复  引用    

#7楼  2006-09-06 08:57 hpy223 [未注册用户]
我一直没有收到你给发的邮件呀!
  回复  引用    

#8楼 [楼主] 2006-09-06 11:51 阿不      
@hpy223
我给你发了邮件了啊。要不你在我的blog上方,给我留言,系统会给我发送邮件,我收到后再给你回邮件,行吗?
  回复  引用  查看    

#9楼  2006-12-01 18:48 Niels      
对于下面的语句
INSERT INTO Articles (ArticleID,ArticleTitle) VALUES(#Articleid#,#ArticleTitle#)
当传到数据库端时,用profile查看,对应的语句是:
INSERT INTO Articles(ArticleID,ArticleTitle)
VALUES( @param0 , @param1),@param0 nvarchar(4000),@param1 nvarchar(4000)
也就是说当使用parameterClass参数时,字符型的参数全部是以nvarchar(4000)传到数据库中的,而事实上这个字段的定义可能为varchar(30), 请问对于insert/update语句的参数,能不能对这些参数设置大小,使传到数据库的大小为varchar(30)
  回复  引用  查看    

#10楼 [楼主] 2006-12-02 08:41 阿不      
可以设置这些参数的大小的,不知道你是否有使用到ParameterMap?如果你有iBatisnet的智能提示,那么你会发现下面这句还有一个size属性,你可以查看一下帮助文档。
<parameter column="Country" property="Country" dbType="nvarchar" type="string" direction="Input"/>
  回复  引用  查看    

#11楼  2007-05-22 22:29 steven love sunny      
最近在自学IBatis,请教个问题,在映射文件中如何将数据库的字段(数据库是英文)转换为中文,即将Xml文件中的<select id="SelectAll"...> Select [CustomID] ......from Customers
</select>(该配置返回的是一个ArrayList),希望将CustomID在页面GridView或DataGirdView中显示为“顾客编号”。谢谢!
  回复  引用  查看    

#12楼 [楼主] 2007-05-30 08:33 阿不      
这个就必须要在GridView中设置HeaderText了。
  回复  引用  查看    

#13楼  2007-06-06 10:31 steven love sunny      
在用IBatis的过程中我有个问题请教,通常我们将配置文件信息(如:providers.config和SqlMap.config)放在默认的地方,WinForm放在应用系统根目录下,现在我将它放在应用系统根目录的Config文件夹下,可是在创建ISqlMapper实例的时候会出错。我的providers.config和SqlMap.config放在同一目录, SqlMap.config中大致这样配置:
<properties embedded="Config.providers.config,IBatisWinFormDemo"/>"
.....
<sqlMaps>
<sqlMap embedded="Maps.Employees.xml,IBatisWinFormDemo"/>
</sqlMaps>
......
而在实例化的时候
private static void InitMapper()
{
ConfigureHandler handler = new ConfigureHandler(Configure);
DomSqlMapBuilder builder = new DomSqlMapBuilder();
FileInfo file = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + @"Config\SqlMap.config");
_mapper = builder.ConfigureAndWatch(file, handler);
}
在执行到最后_mapper = builder.ConfigureAndWatch(file, handler)的时候会出错,请指教,谢谢!
  回复  引用  查看    

#14楼  2007-06-10 10:07 king [未注册用户]
阿不,你的这个DEMO不能插入呀!
  回复  引用    

#15楼 [楼主] 2007-06-10 12:05 阿不      
@king
这边代码已经写了一年多了,那时应该可以的。

不过现在基本不用iBatis了,在实践中发现并没有想象中好用。
  回复  引用  查看    

#16楼  2007-06-11 10:30 neuhawk      
阿不 :有哪个比ibatis更好的?
  回复  引用  查看    

#17楼 [楼主] 2007-06-11 10:39 阿不      
@neuhawk
没有所谓更好的,就要看合不合适了。因为 iBatis 不是一个完全的ORM框架,它无法解决我们数据透明和面向对象访问的需求,很多工作还需要我们做,包括配置文件等等。结合了包括NHibernate,我认为NBear的架构是最优秀的,至少我个人这么理解。现在在使用它了,至少在LINQ出来之前,NBear应该是值得我们去尝试的。
  回复  引用  查看    

#18楼  2007-06-11 15:34 neuhawk      
我也觉得ibatis 配置太麻烦,即使有工具.
因为我们的数据结构可能变动比较大.
NHibernate太大了.
linq可能7月出beta2.
而NBear还没有用过.对了你现在用orm,还是不用,直接用datareader+PO?
  回复  引用  查看    

#19楼 [楼主] 2007-06-11 15:54 阿不      
@neuhawk
到现在,我们已经完全使用ORM了。
要等LINQ可能还得再等上一年。Orcas中已经不包含ADO Entity Framework。尽管我还不是很了解它,但是LINQ还只是纯粹的查询工具,提供强类型的查询语法,可能还无法提高到ORM的概念。
NBear,你可能去了解一下。至少它的架构思路非常优秀,设计和性能的结合还是比较完美的。
  回复  引用  查看    

#20楼  2007-06-11 17:10 neuhawk      
你们的orm是自己开发的吗?
  回复  引用  查看    

#21楼  2007-06-11 17:12 neuhawk      
linq不用等一年,还有,linq实现很多orm的功能了.
如:增删改查,1:N1:1 N:M的关系都有了吧.
其他延时加载等也有了.
  回复  引用  查看    

#22楼 [楼主] 2007-06-11 17:17 阿不      
我们没有自己开发的ORM产品。
能用好ORM已经不错了,何必再造一个轮子呢,而且还不会比现有的更好。
LINQ,我目前的了解还不是很多,还是很期待它的到来的。
  回复  引用  查看    

#23楼  2007-06-11 17:20 neuhawk      
可以透露一下,你们用哪个orm吗?
谢谢,毕竟我们也想知道一下哪个orm实际用起来好用,如果中途更换,很痛苦了,
  回复  引用  查看    

#24楼  2007-06-11 17:22 neuhawk      
今年linq可能会发布正式版本.
下个月可能发布beta2,有点想用linq.
我看了很多orm,文挡齐全的很少,轻量级的也很少.
  回复  引用  查看    

#25楼 [楼主] 2007-06-11 17:33 阿不      
LINQ应该会随着Visual Studio 2008发布吧?今年发布,那Visual Studio 2008也在年底发布?
LINQ,还有它的查询语法,在用.NET 3.5的时候,肯定会用到的。
  回复  引用  查看    

#26楼  2007-08-24 08:33 Flynn      
我学习 IBatis.Net 一个多礼拜了,
用的是 Oracle 数据库
如何给储存过程参数赋值?

我想应该和 update insert 一样的
但是调用的时候老只提示 存储过程 找不到参数

希望用过的人能够指点一下
对了,我用的是 1.6 版
  回复  引用  查看    

#27楼  2007-09-04 17:03 kaoru [未注册用户]
楼上的我这两天遇到和你一样的问题了
用ibatis调用oracle的存储过程,
总是提示传的参数在存储过程中不存在。
不知道你现在解决了没有?
楼主可以帮帮忙么。谢谢
  回复  引用    

#28楼  2007-09-04 20:26 Flynn      
这个问题我在网上找过很多了
就是官方网站上有个 java 的例子
但是也极简单
在.Net 中也没有用?
希望这个问题能够解决
我现在做的东西就在用这个
没有办法只有组SQL
郁闷!!
  回复  引用  查看    

#29楼 [楼主] 2007-09-05 10:26 阿不      
@Flynn @kaoru
不好意思,我现在已经不用ibatis.net了。我用了一段时间,效果不好,而且带来了很多的配置的麻烦。没有减少多少工作,同时增加了维护成本。我现在已经改为NBear了,推荐大家可以去试试:http://nbear.org.cn
  回复  引用  查看    

#30楼  2007-09-05 22:45 Flynn      
@阿不
谢谢
你这么肯定的告诉我
看来我也是要换 ORM 的时候
呵呵
继续学习!!

  回复  引用  查看    


标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2006-05-06 08:47 编辑过


相关链接: