对象集list对象从一种类型转换成另一种list对象(对于里面具体的对象来说的),我们向方法传递一个RowDelegate委托方法作为参数来处理这个繁杂的工作。SqlMapper通过便利对象结果集,对每一个对象执行委托的方法来产生最后需要返回的真正list结果集。注意:请在传递的rowDelegate方法中确保将加工过的对象添加到list对象中,否则list对象将是个空的列表对象。
6.6.5QueryForMapWithRowDelegate
publicdelegatevoidDictionaryRowDelegate(objectkey,objectvalue,objectparameterObject,IDictionarydictionary);publicIDictionaryQueryForMapWithRowDelegate(stringstatementName,objectparameterObject,
stringkeyProperty,stringvalueProperty,DictionaryRowDelegaterowDelegate);
本方法同QueryWithRowDelegate方法类似。不同的是,它用于将对象从一个字典中过滤到另一个字典中。6.6.6QueryForPaginatedList
在本版中这个方法被标注为“废弃”的方法,以后的版本中不再支持此方法。
publicPaginatedListQueryForPaginatedList(stringstatementName,objectparameterObject,intpageSize);
当今是个信息纷纭的年代,用户没有执行数据库查询后经常会返回很多行,而这些行并不是用户想一次性看到的内,因此我们的需求中可能会加上对“分页”的要求。例如,查询结果有10000行,而我们可以给用户看其中的50行,并让用户通过激发系统的前后滚动操作在集合中进行查看数据。这是一种非常普遍存在的需求,因此本框架提供了一个方便实现的方法。
PaginatedList接口包含的方法中提供了对页查询操作的方法——nextPage(),previousPage(),gotoPage();还包含了检查页状态的方法——isFirstPage(),isMiddlePage(),isLastPage(),isNextPageAvailable(),isPreviousPageAvailable(),getPageIndex(),getPageSize()。虽然接口中未提供有效行总数的访问方法,但是通过运行count操作语句就可以获取到这个值。(关于这一点,在天津水环境工程中的映射文件中是有体现的)
注意:
PaginatedList虽然方便使用,但是有一点需要指出,调用此方法时数据提供者会先返回一个大的集合,该结合中包含所有符合查询条件的记录,然后有SqlMapper框架分解成小的集合。对于很大的集合,我们可以使用存储过程或者使用skipResults和maxResults参数调用QueryForList方法。
6.6.6QueryForDictionary,QueryForMap
publicIDictionaryQueryForDictionary(stringstatementName,
objectparameterObject,stringkeyProperty)
publicIDictionary
objectparameterObject,stringkeyProperty);
publicIDictionaryQueryForDictionary(stringstatementName,
objectparameterObject,stringkeyProperty,stringvalueProperty)
publicIDictionary
objectparameterObject,stringkeyProperty,stringvalueProperty);
publicIDictionaryQueryForMap(stringstatementName,
objectparameterObject,stringkeyProperty)
publicIDictionaryQueryForMap(stringstatementName,
objectparameterObject,stringkeyProperty,stringvalueProperty)
QueryForList方法用list对象返回结果对象集。QueryForDictionary方法用一个IDictionary对象返回结果集。每个实体对象的特征值属性由
keyProperty参数制定,keyProperty标识的是返回结果集中对象属性的一个属性名称。例如需要一个Employee对象结果集,则可以用
每个Employee对象的Employee.EmployeeNumber属性值作为字典关键字来产生IDictionary类型的Employee对象集合。如果字典中的对象不需要放回完整的对象,则可以通过增加valueProperty参数,来为字典中的每个对象使用valueProperty值来作为返回值。例如,把EmployeeName作为返回值。
QueryforMap方法是为了和Java中的数据映射框架方法相一致而提供的,它的功能和QueryForDictionary是一致的。
6.6.7Session
在iBATISDataMapper框架中,一个Session就是一个ADOconnection和transaction的容器。使用语法如下:[C#]
using(IDalSessionsession=sqlMap.OpenConnection()){
Accountaccount=sqlMap.QueryForObject(\1)asAccount;}注:
Session不能嵌套使用。如果在一个线程中调用BeginTransaction/OpenConnection多次,或者先调用CommitTransactionorRollbackTransaction,就会产生异常。换言之,每个线程中,每个SqlMapper实例之多含有一个打开的session。
6.6.8Connection
DataMapperAPI包含两个方法来界定数据源连接://Openasession:OpenanADOconnectionpublicvoidOpenConnection()
//Closeasession:ClosetheassociatedADOconnectionpublicvoidCloseConnection()例如:
sqlMap.OpenConnection();
Accountaccount=sqlMap.QueryForObject(\1)asAccount;sqlMap.CloseConnection()
//下面使用构造方法和析构方法完成同样的功能using(IDalSessionsession=sqlMap.OpenConnection()){
Accountaccount=sqlMap.QueryForObject(\1)asAccount;}
6.6.9自动Session
默认情况下,调用SqlMapper实例的任何一个API方法,都会自动执行打开连接会话和关闭连接会话的操作。
这就表示每次调用这些方法,对于数据库而样都是一个独立的过程。大部分情况下,这样的独立过程是满足应用要求的。但是,当需要把一组数据库操作语句作为一个整体运行时,即要么这些语句都执行,要么都不执行,此时就不能用他们了,而需要使用事务进行处理。
[C#]
Itemitem=(Item)sqlMap.executeQueryForObject(\itemId);
item.Description=\//Nosessiondemarcated,soopen/closeconnectionwillbeautomatic(implied)sqlMap.Update(\item);item.Description=newDescription;
item.Description=\//Notransactiondemarcated,soopen/closeconnectionwillbeautomatic(implied)sqlMap.Update(\item);注:
当设计数据库操作语句时,一定要仔细琢磨数据源连接会话的情况。自动处理连接会话虽然方便,但是在对数据库进行多条更新操作时就可能会引来麻烦。在本例中,第二次调用sqlMap.Update如果运行失败,item.Description属性也会被更新为新的描述”TX1”,因为第一个update调用是成功的。这是任何一个用户都不希望看到的结果。
6.6.10Transaction
DataMapperAPI中含有事务(Transaction)边界的定义方法,事务由开始、提交/回滚构成。可以从SqlMapper实例调用这些方法。//Beginatransactionalsession:OpenaconnectionandbeginanADOtransactionpublicvoidBeginTransaction()
//Beginatransactionalsession:OpenaconnectionisspecifiedandbeginanADOtransactionpublicvoidBeginTransaction(boolopenConnection)
//Beginatransactionalsession:OpenaconnectionandbeginanADOtransaction//withthespecifiedIsolationLevel
publicvoidBeginTransaction(IsolationLevelisolationLevel)
//Beginatransactionalsession:OpenaconnectionisspecifiedandbeginanADOtransaction//withthespecifiedIsolationLevel
publicvoidBeginTransaction(boolopenConnection,IsolationLevelisolationLevel)
//Commitasession:CommittheADOtransactionandclosetheconnectionpublicvoidCommitTransaction()
//Commitasession:CommittheADOtransactionandclosetheconnectionifspecifiedpublicvoidCommitTransaction(boolcloseConnection)
//RollBackasession:RollBacktheADOtransactionandclosetheconnectionpublicvoidRollBackTransaction()
//RollBackasession:RollBacktheADOtransactionandclosetheconnectionifspecifiedpublicvoidRollBackTransaction(boolcloseConnection)应用事务的实例:try{
sqlMap.BeginTransaction();
Itemitem=(Item)sqlMap.QueryForObject(\itemId);item.Description=newDescription;sqlMap.Update(\item);sqlMap.CommitTransaction();}catch{
sqlMap.RollBackTransaction();}
//With\syntax
using(IDalSessionsession=sqlMap.BeginTransaction()){
Itemitem=(Item)sqlMap.QueryForObject(\itemId);item.Description=newDescription;sqlMap.Update(\item);session.Complete();//Commit}
应用分布式事务的例子:
usingIBatisNet.Common.Transaction;
using(TransactionScopetx=newTransactionScope()){
sqlMapSqlServer.OpenConnection();//事务会自动进行连接
account=sqlMapSqlServer.QueryForObject(\accountId)asAccount;account.FirstName=\sqlMapSqlServer.Update(account);sqlMapSqlServer.CloseConnection();sqlMapOracle.OpenConnection();//事务会自动进行连接
product=sqlMapOracle.QueryForObject(\productId)asProduct;product.Quantity=1000;
sqlMapOracle.Update(product);sqlMapOracle.CloseConnection();tx.Complete();//Commit}
需要重点指出的一点是要确保该类的每个实例都需要调用Close()方法。确保每个实例都执行关闭最容易的方法是在C#的using语法编写程序块。在using代码块的末尾调用事务的Dispose()方法时,只有调用TransactionScope类实例的Complete()方法时,范围内的事务才会被提交。
TransactionScope类不支持事务嵌套。
6.6.11程序举例:
Example4.18.ExecutingUpdate(insert,update,delete)[C#]
Productproduct=newProduct();product.Id=1;
product.Description=“ShihTzu”;
intkey=sqlMap.Insert(“insertProduct”,product);
Example4.19.ExecutingQueryforObject(select)[C#]intkey=1;
Productproduct=sqlMap.QueryForObject(“getProduct”,key)asProduct;
Example4.20.ExecutingQueryforObject(select)WithPreallocatedResultObject[C#]
Customercustomer=newCustomer();sqlMap.BeginTransaction();
sqlMap.QueryForObject(“getCust”,parameterObject,customer);sqlMap.QueryForObject(“getAddr”,parameterObject,customer);sqlMap.CommitTransaction();
Example4.21.ExecutingQueryforList(select)[C#]
IListlist=sqlMap.QueryForList(“getProductList”,null);
Example4.22.Auto-Open/Close[C#]
//WhenOpenConnectionisnotcalled,thestatementswillauto-Open/Close.intkey=sqlMap.Insert(“insertProduct”,product);
Example4.23.ExecutingQueryforList(select)WithResultBoundaries[C#]
Listlist=sqlMap.queryForList(“getProductList”,null,0,40);
Example4.24.ExecutingQuerywithaRowHandler(select)[C#]
publicvoidRowHandler(objectobj,IListlist){
Productproduct=(Product)object;product.Quantity=10000;}
SqlMapper.RowDelegatehandler=newSqlMapper.RowDelegate(this.RowHandler);IListlist=sqlMap.QueryWithRowDelegate(\null,handler);
Example4.25.ExecutingQueryforPaginatedList(select)[C#]
PaginatedListlist=sqlMap.QueryForPaginatedList(“getProductList”,null,10);list.NextPage();list.PreviousPage();
Example4.26.ExecutingQueryforMap[C#]
IDictionarymap=sqlMap.QueryForMap(“getProductList”,null,“productCode”);Productp=(Product)map[“EST-93”];
6.6.12SqlMap活动日志
iBATISDataMapper框架内部通过仿效ApacheLog4Net方式,利用数据库记录SqlMap的活动日志。内部日志可以使用NoOpLogger,ConsoleOutLogger,TraceLogger中的一种来完成日志记录,也可以使用外部日志包(如ApacheLog4Net)来完成。为使iBATIS产生活动日志,须要在工程配置文件(App.Config或Web.Config)中设置下面的XML节点:
应用程序配置中还需要设置一种(三种中的一种)执行日志的节点,如下所示:日志方法一: