上文以SqlHelper为例说明了面向对象中封装的好处,但是上文只是简单封装,考虑下面代码的情况:
public static Activate GetByCode(string code)
{
List<SqlParameter> paraList = new List<SqlParameter>();
paraList.Add(new SqlParameter("@activateCode", code));
using (SqlDataReader reader = SqlHelper.ExecuteReader(Configuration.ConnectionString, CommandType.StoredProcedure, "GetActivateByCode", paraList.ToArray()))
{
while (reader.Read())
{
Activate result = new Activate();
result.Id = Utility.GetDbValue(reader, "Id", -1);
result.CollegeId = Utility.GetDbValue(reader, "CollegeId", -1);
result.ActivateCode = Utility.GetDbValue(reader, "ActivateCode", "");
result.Activated = Utility.GetDbValue(reader, "Activated", false);
result.StudentId = Utility.GetDbValue(reader, "StudentId", "");
result.StudyCenter = Utility.GetDbValue(reader, "StudyCenter", "");
result.StudentContact = Utility.GetDbValue(reader, "StudentContact", "");
result.Major = Utility.GetDbValue(reader, "Major", "");
result.Grade = Utility.GetDbValue(reader, "Grade", "");
result.CreatedTime = Utility.GetDbValue(reader, "CreatedTime", new DateTime(1900,1,1));
result.Disabled = Utility.GetDbValue(reader, "Disable", false);
return result;
}
}
return null;
}
如果这个查询语句要返回很多值的情况下,我们还要对查询结构进行一一匹配,map到定义好的数据结构<Activate>。我们希望对这个SqlHelper进行更高层次的封装,使他的返回结果自动map,像下面这样:
public static ACTIVATE GetByStudentId(string studentId)
{
IDbConnection connection = null;
try
{
connection = DAOHelper.GetConnection();
connection.Open();
//Query方法不仅执行了查询,并把返回的数据自动map成了ACTIVATE类型的数据,
//即数据库内的Id对应ACTIVATE的Id,数据库内的CollegeId对应ACTIVATE的CollegeId
//这个方法支持泛型的返回结果匹配
var list = connection.Query<ACTIVATE>(@"GetActivateByCode",studentId,CommandType.StoredProcedure)
if (list != null && list.Count > 0)
return list[0];
}
catch (Exception ex)
{
Trace.Write(ex);
return null;
}
finally
{
connection.Close();
}
return null;
}
像上面代码这样,这是对ADO.NET更为抽象的封装,他操作数据库的方式更加简单便捷,并支持返回结果的自动map。(这种技术称之为ORM)
值得注意的是,虽然越抽象的封装越方便易用,但也越不灵活,想想看如果以上代码中ACTIVATE的字段变掉怎么应对?所以,凡事都有利弊的两面,到底需要多大程度的封装,还要看我们项目的需求。