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

解决方案 »

  1.   

    有些情况下,非类型化的 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, value);
    }
    public void Remove(User value) {
    List.Remove(value);
    }
    public bool Contains(User value) {
    return (List.Contains(value));
    }
    }映射到自定义集合:
    将我们的关系数据映射到自定义集合的过程与我们对自定义实体执行的过程非常相似。我们不再创建一个实体并将其返回,而是将该实体添加到集合中并循环到下一个:public UserCollection GetAllUsers() {
    SqlConnection connection = new SqlConnection(CONNECTION_STRING);
    SqlCommand command =new SqlCommand("GetAllUsers", connection);
    SqlDataReader dr = null;
    try{
    connection.Open();
    dr = command.ExecuteReader(CommandBehavior.SingleResult);
    UserCollection users = new UserCollection();
    while (dr.Read()){
    users.Add(PopulateUser(dr));
        }
    return users;
    }finally{
    if (dr != null && !dr.IsClosed){
    dr.Close();
        }
    connection.Dispose();
    command.Dispose();
    }
    }添加自定义行为:
    示例一
    public User FindUserById(int userId) {
    foreach (User user in List) {
    if (user.UserId == userId){
    return user;
        }
    }
    return null;
    }
    示例二
    public UserCollection FindMatchingUsers(string search) {
    if (search == null){
    throw new ArgumentNullException("search cannot be null");
    }
    UserCollection matchingUsers = new UserCollection();
    foreach (User user in List) {
    string userName = user.UserName;
    if (userName != null && userName.StartsWith(search)){
    matchingUsers.Add(user);
        }
    }
    return matchingUsers;
    }绑定自定义集合:  [转自:51item.net]  
    自定义集合绑定到web控件和DataSet一样很简单(这是因为 CollectionBase 实现了用于绑定的 Ilist)。自定义集合可以作为任何控件的 DataSource,而 DataBinder.Eval 只能像您使用 DataSet 那样使用——UserCollection users = DAL.GetAllUsers();
    repeater.DataSource = users;
    repeater.DataBind();<!-- HTML -->
    <asp:Repeater onItemDataBound="r_IDB" ID="repeater" Runat="server">
    <ItemTemplate>
    <asp:Label ID="userName" Runat="server">
    <%# DataBinder.Eval(Container.DataItem, "UserName") %><br />
    </asp:Label>
    </ItemTemplate>
    </asp:Repeater>高级内容:
    1、并发
    2、性能
    3、排序与筛选
    4、代码生成
    5、ORM映射
    6、泛型
    7、可以为空的类型
    8、迭代程序【强烈推荐参考:《DataSet与自定义实体类以及集合的比较》】
    DataSets vs. Collections by Dino Esposito对比分析了DataSet, Typed DataSet和Custom Entities and Collections(定制业务实体和集合)作为multi-tier之间的数据传递,并阐述各自的适用情况(When to Use Which)。文章建议:在小型项目中,考虑到预算、截至时间等因素,可以使用DataSet快速开发。如果项目时间长、投入多,业务逻辑复杂,则使用自定义实体类以及集合,对于维护、扩展、灵活、代码的优雅、单元测试等,都能带来益处。前期的投入是值得的。
     
     
      

  2.   

    掌握 ASP.NET 之路:自定义实体类简介
    http://blog.csdn.net/octverve/archive/2007/09/07/1776617.aspx
      

  3.   

    ls的不错,顶了。
    你看微软自己的petshop也不用dataset,太重量级了。
      

  4.   

    自定义实体 (领域模型) 与 DataSet/DataTable (表模型)最明显的区别就是:前者是强类型的,
    虽然可以选择 强类型DataSet,但是,相对来说,比较耗性能
      

  5.   


    分层策略充分考虑OO思想,极大的体现了可扩展性等优点,好处多多。不过为几个功能费周折也没必要。dataset 把数据库的架构搬到了内存中,很强大\性能下降,过于封装。
    至于用什么,还是需要视实际情况而定,牛刀宰鸡或者鸡刀宰毕竟都不好啊。