在数据库访问的时候,很多情况下从数据库返回的是一个结果集(List),怎么样把它转换为我们在C#代码中定义的实体类型?
Spring.Net定义了三组接口和委托用于回调,开发人员需要自己实现或定义这些回调方法
(1)IResultSetExtractor/ResultSetExtractorDelegate:传递一个IDataReader对象,开发人员可以利用该对象迭代数据并返回结果对象。
(2)IRowCallback/RowCallbackDelegate:传递一个IDataReader对象,可用于处理当前行。返回值为void,因此在实现IRowCallback接口时一般将类实现为有状态的(按:也就是说实现类需要定义自己的字段来保存回调的结果),在使用匿名委托时,一般用本地变量来保存回调的结果。
(3)IRowMapper/RowMapperDelegate:传递一个IDataReader对象,用以处理当前行并返回一个对应于当前行的对象。
我们这次主要讲解一下第三种.
IRowMapper可以让开发人员专注于如何将结果集中的一行映射为一个对象。框架会负责使用IDataReader进行迭代并创建一个IList来保存结果对象.
Dao层的代码如下:
//必须要继承AdoDaoSupport,
//AdoDaoSupport中集成了所有连接数据库,执行访问数据库,关闭数据的所有操作
public class PersonDao:AdoDaoSupport
{
public IList GetPersonInfoDetailsByPersonId(string personId)
{
//定义返回 的对象
IList result = new List();
//定义用于装载参数的集合
IDbParameters parameters = AdoTemplate.CreateDbParameters();
//添加参数
parameters.AddWithValue("PersonId", new Guid(personId));
//使用QueryWithRowMapper方法访问数据库,返回结果集
result = AdoTemplate.QueryWithRowMapper(
CommandType.StoredProcedure,"SP_GetPersonInfoByPersonId", new PersonMapper(), parameters);
return result;
}
}
PersonMapper的定义如下:
逐行将数据转换为实体类
public class PersonMapper : IRowMapper where T : Person, new()
{
T IRowMapper.MapRow(IDataReader dataReader, int rowNum)
{
T view = new T();
if (DataReaderRowFilter.RowFilter(dataReader, "PersonId"))
view.PersonId = dataReader.GetValueOrDefault("PersonId");
if (DataReaderRowFilter.RowFilter(dataReader, "PersonName"))
view.PersonName = dataReader.GetValueOrDefault("PersonName");
if (DataReaderRowFilter.RowFilter(dataReader, "Age"))
view.Age = dataReader.GetValueOrDefault("Age");
return view;
}
}
DataReaderRowFilter.RowFilter定义如下:
判断DataReader中是否有某列
public class DataReaderRowFilter
{
public static bool RowFilter(IDataReader dataReader, string columnName)
{
dataReader.GetSchemaTable().DefaultView.RowFilter = string.Format("ColumnName='{0}'", columnName);
return dataReader.GetSchemaTable().DefaultView.Count > 0;
}
}
GetValueOrDefault定义如下:
public static T GetValueOrDefault(this IDataReader reader, string columnName)
{
int index = reader.GetOrdinal(columnName);
T returnValue = default(T);
if (!reader.IsDBNull(index))
{
returnValue = (T)Convert.ChangeType(reader[columnName], typeof(T));
//returnValue = (T)reader[columnName];
}
return returnValue;
}
如果映射的逻辑比较少,并且需要使用访问本地变量的时候,使用委托会更加方便(参考官方文档):
public virtual IList GetCustomersWithDelegate()
{
return AdoTemplate.QueryWithRowMapperDelegate(CommandType.Text, cmdText,
delegate(IDataReader dataReader, int rowNum)
{
Customer customer = new Customer();
customer.Address = dataReader.GetString(0);
customer.City = dataReader.GetString(1);
customer.CompanyName = dataReader.GetString(2);
customer.ContactName = dataReader.GetString(3);
customer.ContactTitle = dataReader.GetString(4);
customer.Country = dataReader.GetString(5);
customer.Fax = dataReader.GetString(6);
customer.Id = dataReader.GetString(7);
customer.Phone = dataReader.GetString(8);
customer.PostalCode = dataReader.GetString(9);
customer.Region = dataReader.GetString(10);
return customer;
});
}