【问题标题】:How can I improve my data access classes in ASP.NET如何改进 ASP.NET 中的数据访问类
【发布时间】:2012-03-18 15:48:05
【问题描述】:

我已经编码了一段时间,但仍然认为自己是初学者。我使用带有内置 SQL 语句的非常简单的 ADO.NET 类。我想听听社区关于我做错了什么以及如何改进,以及建议的下一步是将我的编码纳入当前标准的步骤。

我真的对尝试 EF 很感兴趣,尽管我似乎找不到适合我的 BLL 和 DAL 课程的教程,所以希望能指出正确的方向。

基本上,如果我有一个 Gift,我会创建一个 Gift 类 (BLL\Gift.cs):

using MyProject.DataAccessLayer;

namespace MyProject.BusinessLogicLayer
{
public class Gift
{

    public int GiftID { get; set; }
    public string GiftName { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }

    public static Gift GetGiftByID(int GiftID)
    {
        GiftDAL dataAccessLayer = new GiftDAL();
        return dataAccessLayer.GiftsSelectByID(GiftID);
    }

    public void DeleteGift(Gift myGift)
    {
        GiftDAL dataAccessLayer = new GiftDAL();
        dataAccessLayer.DeleteGift(myGift);
    }

    public bool UpdateGift(Gift myGift)
    {
        GiftDAL dataAccessLayer = new GiftDAL();
        return dataAccessLayer.UpdateGift(myGift);
    }

    public int InsertGift(string GiftName, string Description, decimal Price)
    {
        Gift myGift = new Gift();
        myGift.GiftName = GiftName;
        myGift.Description = Description;
        myGift.Price = Price;

        GiftDAL dataAccessLayer = new GiftDAL();
        return dataAccessLayer.InsertGift(myGift);
    }
}
}

然后我有一个 DAL 类来保存我的连接字符串 (DAL\sqlDAL.css):

namespace MyProject.DataAccessLayer
{
public class SqlDataAccessLayer
{
    public readonly string _connectionString = string.Empty;

    public SqlDataAccessLayer()
    {
        _connectionString = WebConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString;
        if (string.IsNullOrEmpty(_connectionString))
        {
            throw new Exception("No database connection String found");
        }
    }
}
}

然后是一个 DAL 类 (DAL\giftDAL.cs),其中我展示了几个方法(更新和删除):

using MyProject.BusinessLogicLayer;

namespace MyProject.DataAccessLayer
{
public class GiftDAL : SqlDataAccessLayer
{
    public bool UpdateGift(Gift GifttoUpdate)
    {
        string UpdateString = "";
        UpdateString += "UPDATE Gifts SET";
        UpdateString += "GiftName = @GiftName";
        UpdateString += ",Description = @Description ";
        UpdateString += ",Price = @Price ";
        UpdateString += " WHERE GiftID = @GiftID";

        int RowsAffected = 0;

        try
        {
            using (SqlConnection con = new SqlConnection(_connectionString))
            {
                using (SqlCommand cmd = new SqlCommand(UpdateString, con))
                {
                    cmd.Parameters.AddWithValue("@GiftName", GifttoUpdate.GiftName);
                    cmd.Parameters.AddWithValue("@Description", GifttoUpdate.Description);
                    cmd.Parameters.AddWithValue("@Price ", GifttoUpdate.Price);
                    cmd.Parameters.AddWithValue("@GiftID", GifttoUpdate.GiftID);
                    con.Open();
                    RowsAffected = cmd.ExecuteNonQuery();
                }
            }
        }
        catch (Exception ex)
        {
            Utils.LogError(ex.Message, ex.InnerException == null ? "N/A" : ex.InnerException.Message, ex.StackTrace);
        }

        return (RowsAffected == 1);

    }

    public void DeleteGift(Gift GifttoDelete)
    {
        string DeleteString = "";
        DeleteString += "DELETE FROM GIFTS WHERE GIFTID = @GiftID";

        try
        {
            using (SqlConnection con = new SqlConnection(_connectionString))
            {
                using (SqlCommand cmd = new SqlCommand(DeleteString, con))
                {
                    cmd.Parameters.AddWithValue("@GiftID", GifttoDelete.GiftID);
                    con.Open();
                    cmd.ExecuteNonQuery();

                }
            }
        }
        catch (Exception ex)
        {
            Utils.LogError(ex.Message, ex.InnerException == null ? "N/A" : ex.InnerException.Message, ex.StackTrace);
        }
    }


}
}

那么看看这个,你会建议我如何改进代码(如果我继续使用 ADO.NET)以及我的下一步是学习 EF - 还是有更好的选择?

干杯, 罗比

【问题讨论】:

  • 我相信你应该把你的业务逻辑移动到SQL Server存储过程中。想想这个,只要你的一个表发生变化,你就必须改变代码,这意味着你应该调整您的代码再次编译+发布。创建一个库来调用这些存储过程。
  • @Myra:并非所有业务逻辑都可以在存储过程中表达。此外,数据层在概念上 (IMO) 是业务逻辑的错误位置。它更难测试,而且不便携。例如。您不能切换到内存数据库中的轻量级 SQLite 进行测试。在域模型和持久存储之间使用对象关系映射器可以最大限度地减少匹配两个世界中任何一个世界中的更改所需的工作量。所以我的建议是:将业务逻辑保留在代码中,并将数据库用作数据存储。 SP 应该只涉及数据问题,而不是业务逻辑。

标签: asp.net


【解决方案1】:

(对我而言)一直很重要的一件事是课程的可测试性。我在您的代码中看到了很多明确的对象构造。您的 Gift BL 类显式依赖于 GiftDAL,这使得测试 Gift 类变得非常困难。尝试通过对 GiftDAL 进行抽象(例如接口)来减少类之间的耦合,并将其从外部提供给 Gift (Dependency Injection)。

一本关于优秀软件设计原则的好书是Clean Code by Robert C. Martin。他建立了SOLID 原则。看看吧!

另外,请注意,您现在将持久性包含在业务逻辑类(或也称为域模型)中。这可以做到 (Active Record),但现在人们通常选择一种不同的方法,将他们的域模型与任何基础设施分开。广义的想法是:需要以某种方式存储对象这一事实很重要,但对业务逻辑本身并不重要,因此应尽可能将关注点分开。通常Object Relational Mapper、.NET 的NHibernateEntity Framework 是OR 映射器的两个示例。

【讨论】:

  • 这是很好的反馈,非常感谢。我似乎经常构造我的对象。例如,在我的 Page_Load 中,如果我将礼物绑定到一系列文本框,我将执行以下操作:' if Gift myGift = Gift.GetGiftByID(Convert.ToInt32(Session["GiftIDtoEdit"])); txtGiftName.Text = myGift.GiftName;等
【解决方案2】:

如果您想坚持使用 ADD.NET,那么为什么不查看 Microsoft Enterprise Library 中的Data Application Block(当前版本为 2011 年 5 月 5.0 版)-它将允许您编写供应商(MS-SQL/Oracle 等)中性代码很容易,并且大部分样板代码都会被包装。

This 可能是我能找到的最简单/最短的教程,可以帮助您入门。但是,MSDN 链接有大量信息,请参阅关键场景部分以快速入门。

另一个建议是使用TransactionScope 来管理事务(而不是直接使用 DbTransaction 对象)。

说了我会推荐使用实体框架(或任何类似的 OR 映射器工具 - 例如检查 NHibernet),因为这样您就不必为基本的 CRUD 操作编写典型代码。就您的困境而言,这里是帮助您入门的基本代码 sn-p - 我正在使用 EF 4.1 和 Code-First 方法、POCO 实体和 Fluent API:

实体:

public class Gift
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
}

数据访问层:

public class MyDbContext : DbContext
{
   public DbSet<Gift> Gifts { get; set; }

   public MyDbContext () : base("name=[ConnStringName]") {}

   protected override void OnModelCreating(DbModelBuilder modelBuilder)
   {
      // Fluent API to provide mapping - you may use attributes in entity class
      var giftConfig = modelBuilder.Entity<Gift>();
      giftConfig.Property(p => p.Id).HasColumnName("GiftID");
      giftConfig.Property(p => p.Name).HasColumnName("GiftName");
      giftConfig.Property(p => p.Description).HasColumnName("Description");
      giftConfig.Property(p => p.Price).HasColumnName("Price");
      giftConfig.HasKey(p => p.Id);

      base.OnModelCreating(modelBuilder); 
   }
}

业务层:

public static class GiftManager
{
   public static Gift GetById(int id)
   {
      using(var db = new MyDbContext())
      {
         return db.Gifts.Find(id);
      }
   }

   public static void Add(Gift gift)
   {
      using(var db = new MyDbContext())
      {
         // do validation
         ...

         db.Gifts.Add(gift);

         // do auditing
         ...

         db.SaveChanges();
      }
   }

   public static void Update(Gift gift)
   {
      using(var db = new MyDbContext())
      {
         // do validation
         ...

         var entity = db.Sessions.Find(gift.Id);
         entity.Name = gift.Name;
         entity.Description = gift.Description;
         entity.Price = gift.Price;

         // do auditing
         ...

         db.SaveChanges();
      }
   }

}

【讨论】:

  • 谢谢,我从来没有听说过这个:-o。我会四处看看以获取更多信息,但现在 EF 不是 Microsoft 首选的数据访问技术吗?
  • @RobbieMills,MS 在 OR-Mapping 工具方面有点晚了 - EF 仍在不断发展产品,还有一段路要走。所以是的,它正在积极开发中(但 ADO.NET 仍然是底层数据访问机制。您会看到更多关注 EF,因为它相对更不用说,它极大地提高了生产力。
【解决方案3】:

我有一个 dal 类,它的方法只返回可绑定的对象,如数据表、列表等。没有更多或更少。然后所有业务逻辑自然发生在 aspnet 应用程序的代码中。在大多数情况下,制作支持对象的工作量太大而且矫枉过正。我对数据表和列表很满意。

【讨论】:

  • 支持对象是什么意思?对不起,我不明白这个词。 :-)
  • 我指的是一个 aspnet 应用程序,您可以在其中将数据应用于网格、下拉菜单等。
  • 很有趣,几个月后我又读了一遍。 “支持对象”是指对象关系映射器。基本上它将是一个代表您的数据库表的类。例如,您要将表“Car”转换为名为“Car”的 c# 类,并将表中的所有列映射到类成员变量。不过,有很多简单的方法可以做到这一点,使用 LINQ、实体框架或任何其他 OR-mapper。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-28
  • 1970-01-01
  • 2012-06-21
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 2016-12-03
相关资源
最近更新 更多