日期:2014-05-18  浏览次数:20390 次

用Dataset还是用实体类?请教下
感觉好多的三层都是用实体类来传数据,为什么不用DataSet?这两者各有什么优缺点?

------解决方案--------------------
有些情况下,非类型化的 DataSet 可能并非数据操作的最佳解决方案。本指南的目的就是探讨 DataSet 的一种替代解决方案,即:自定义实体与集合。(

使用自定义实体类和集合代替DataSet2007-05-31 20:07使用自定义实体类和集合代替DataSet
--------------------------------------------

DataSet的问题:
1、缺少抽象,开发人员必须了解其基础架构;
2、弱类型,返回的是System.Object,必须进行类型转换Convert.ToInt32等之后才能使用,降低了效率,增加了出错的可能性;
3、不是面向对象的,无法充分利用OO的技术。
使用DataSet,它的缺点将在复杂系统中成倍的扩大。

自定义实体类的挑战:
要求更多的代码。我们不是简单地获取数据并自动填充 DataSet,而是获取数据并手动将数据映射到自定义实体(必须先创建好)。由于这个工作是重复的,我们可以使用代码生成工具或者ORM映射。

自定义实体类的代码示例:
public class User {
#region "Fields and Properties "
private int userId;
private string userName;
private string password;
public int UserId {
get { return userId; }
set { userId = value; }
}
public string UserName {
get { return userName; }
set { userName = value; }
}
public string Password {
get { return password; }
set { password = value; }
}
#endregion
#region "Constructors "
public User() {}
public User(int id, string name, string password) {
this.UserId = id;
this.UserName = name;
this.Password = password;
}
#endregion
}

自定义实体类的优点:
1、可以让我们利用继承和封装等OO技术;
2、可以添加自定义行为;
3、属于强类型,可以获得代码自动完成功能(IntelliSense);
4、属于强类型,不太需要容易出错的强制类型转换。

对象和关系的映射:
public User GetUser(int userId) {
SqlConnection connection = new SqlConnection(CONNECTION_STRING);
SqlCommand command = new SqlCommand( "GetUserById ", connection);
command.Parameters.Add( "@UserId ", SqlDbType.Int).Value = userId;
SqlDataReader dr = null;
try{
connection.Open();
dr = command.ExecuteReader(CommandBehavior.SingleRow);
if (dr.Read()){
User user = new User();
user.UserId = Convert.ToInt32(dr[ "UserId "]);
user.UserName = Convert.ToString(dr[ "UserName "]);
user.Password = Convert.ToString(dr[ "Password "]);
return user;
}
return null;
}finally{
if (dr != null && !dr.IsClosed){
dr.Close();
}
connection.Dispose();
command.Dispose();
}
}

以上代码还保留着DataSet弱类型需要转换这样的缺点,所以应该进一步改进,即将映射的转换过程提取到一个函数中,使这段代码能够重复使用——

public User PopulateUser(IDataRecord dr) {
User user = new User();
user.UserId = Convert.ToInt32(dr[ "UserId "]);
//检查 NULL 的示例
if (dr[ "UserName "] != DBNull.Value){
user.UserName = Convert.ToString(dr[ "UserName "]);
}
user.Password = Convert.ToString(dr[ "Password "]);
return user;
}

需要说明1:我们不对映射函数使用 SqlDataReader,而是使用 IDataRecord。这是所有 DataReader 实现的接口。使用 IDataRecord 使我们的映射过程独立于供应商。也就是说,我们可以使用上一个函数从 Access 数据库中映射 User,即使它使用 OleDbDataReader 也可以。如果您将这个特定的方法与 Provider Model Design Pattern(链接 1、链接 2)结合使用,您的代码就可以轻松地用于不同的数据库提供程序。
需要说明2:数据访问是否该和自定义实体类放在一起?为了扩展和维护的方便,通常应该将数据访问层和业务层明确分离。

自定义集合:
简单的解决方案是使用Arraylist,但它的问题和DataSet相关,即也是弱类型,无法添加自定义行为。幸亏 Microsoft .NET Framework 提供了一个专门为了此目的而继承的类:CollectionBase。CollectionBase 的工作原理是,将所有类型的对象都存储在专有 Arraylist 中,但是通过只接受特定类型(例如 User 对象)的方法来提供对这些专有集合的访问。代码示例——

public class UserCollection :CollectionBase {
public User this[int index] {
get {return (User)List[index];}
set {List[index] = value;}
}
public int Add(User value) {
return (List.Add(value));
}
public int IndexOf(User value) {
return (List.IndexOf(value));
}
public void Insert(int index, User value) {
List.Insert(index, v