用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