【问题标题】:Best way to handle exception in ADO.Net repository pattern在 ADO.Net 存储库模式中处理异常的最佳方法
【发布时间】:2016-01-03 18:14:29
【问题描述】:

我为 ado.net 设计了小型存储库模式。现在我无法以正确的方式处理异常。如果发生任何错误,我想将错误推送到调用环境。如果没有发生错误,则结果集将被推送到调用环境。

我有一个名为AdoRepository 的存储库,它扩展了其他存储库类,如employee 等。我们从mvc 控制器调用employee repository function。所以我想将错误从employee repository 推送到 mvc 控制器,如果在数据获取期间发生任何错误,如果没有发生错误,那么数据将被发送到 mvc 控制器。这是我的完整代码。请查看并分享最佳设计的想法。如果可能,请在此处粘贴更正后的代码。

基础存储库

 public abstract class AdoRepository<T> where T : class
    {
        private SqlConnection _connection;
        public virtual void Status(bool IsError, string strErrMsg)
        {

        }

        public AdoRepository(string connectionString)
        {
            _connection = new SqlConnection(connectionString);
        }

        public virtual T PopulateRecord(SqlDataReader reader)
        {
            return null;
        }

        public virtual void GetDataCount(int count)
        {

        }

        protected IEnumerable<T> GetRecords(SqlCommand command)
        {
            var reader = (SqlDataReader) null;
            var list = new List<T>();
            try
            {
                command.Connection = _connection;
                _connection.Open();
                reader = command.ExecuteReader();
                while (reader.Read())
                {
                    list.Add(PopulateRecord(reader));
                }

                reader.NextResult();
                if (reader.HasRows)
                {
                    while (reader.Read())
                    {
                        GetDataCount(Convert.ToInt32(reader["Count"].ToString()));
                    }
                }
                Status(false, "");
            }
            catch (Exception ex)
            {
                Status(true, ex.Message);
            }
            finally
            {
                // Always call Close when done reading.
                reader.Close();
                _connection.Close();
                _connection.Dispose();
            }

            return list;
        }

        protected T GetRecord(SqlCommand command)
        {
            var reader = (SqlDataReader)null;
            T record = null;

            try
            {
                command.Connection = _connection;
                _connection.Open();

                reader = command.ExecuteReader();
                while (reader.Read())
                {
                    record = PopulateRecord(reader);
                    Status(false, "");
                    break;
                }
            }
            catch (Exception ex)
            {
                Status(true, ex.Message);
            }
            finally
            {
                reader.Close();
                _connection.Close();
                _connection.Dispose();
            }
            return record;
        }

        protected IEnumerable<T> ExecuteStoredProc(SqlCommand command)
        {
            var reader = (SqlDataReader)null;
            var list = new List<T>();
            try
            {
                command.Connection = _connection;
                command.CommandType = CommandType.StoredProcedure;
                _connection.Open();
                reader = command.ExecuteReader();

                while (reader.Read())
                {
                    var record = PopulateRecord(reader);
                    if (record != null) list.Add(record);
                }
            }
            finally
            {
                // Always call Close when done reading.
                reader.Close();
                _connection.Close();
                _connection.Dispose();
            }
            return list;
        }
    }

StudentRepository which extend base AdoRepository
-----------------------------------------------
public class StudentRepository : AdoRepository<Student>
    {
        public int DataCounter { get; set; }
        public bool hasError { get; set; }
        public string ErrorMessage { get; set; }

        public StudentRepository(string connectionString)
            : base(connectionString)
        {
        }

        public IEnumerable<Student> GetAll()
        {
            // DBAs across the country are having strokes 
            //  over this next command!
            using (var command = new SqlCommand("SELECT ID, FirstName,LastName,IsActive,StateName,CityName FROM vwListStudents"))
            {
                return GetRecords(command);
            }
        }
        public Student GetById(string id)
        {
            // PARAMETERIZED QUERIES!
            using (var command = new SqlCommand("SELECT ID, FirstName,LastName,IsActive,StateName,CityName FROM vwListStudents WHERE Id = @id"))
            {
                command.Parameters.Add(new ObjectParameter("id", id));
                return GetRecord(command);
            }
        }

        public IEnumerable<Student> GetStudents(int StartIndex, int EndIndex, string sortCol, string sortOrder)
        {
            string strSQL = "SELECT * FROM vwListStudents WHERE ID >=" + StartIndex + " AND ID <=" + EndIndex;
            strSQL += " ORDER BY " + sortCol + " " + sortOrder;
            strSQL += ";SELECT COUNT(*) AS Count FROM vwListStudents";
            var command = new SqlCommand(strSQL);
            return GetRecords(command);
        }

        public override Student PopulateRecord(SqlDataReader reader)
        {
            return new Student
            {
                ID = Convert.ToInt32(reader["ID"].ToString()),
                FirstName = reader["FirstName"].ToString(),
                LastName = reader["LastName"].ToString(),
                IsActive = Convert.ToBoolean(reader["IsActive"]),
                StateID = Convert.ToInt32(reader["StateID"].ToString()),
                StateName = reader["StateName"].ToString(),
                CityID = Convert.ToInt32(reader["CityID"].ToString()),
                CityName = reader["CityName"].ToString()
            };
        }

        public override void GetDataCount(int count)
        {
            DataCounter = count;
        }

        public override void Status(bool IsError, string strErrMsg)
        {
            hasError = IsError;
            ErrorMessage = strErrMsg;
        }
}

像下面这样从 mvc 控制器调用 StudentRepository

​​>
 public class StudentController : Controller
    {
        private StudentRepository _data;

        public StudentController()
        {
            _data = new StudentRepository(System.Configuration.ConfigurationManager.ConnectionStrings["StudentDBContext"].ConnectionString);
        }

        // GET: Stuent
        public ActionResult List(StudentListViewModel oSVm)
        {

            StudentListViewModel SVm = new StudentListViewModel();
            SVm.SetUpParams(oSVm);
            SVm.Students = _data.GetStudents(SVm.StartIndex, SVm.EndIndex, SVm.sort, oSVm.sortdir).ToList();
            SVm.RowCount = _data.DataCounter;

            return View("ListStudents",SVm);
        }
    }

【问题讨论】:

    标签: c# asp.net-mvc exception-handling ado.net repository-pattern


    【解决方案1】:

    我不明白这一点:

            catch (Exception ex)
            {
                Status(true, ex.Message);
            }
    

    只是不要捕获异常并让它冒泡给调用者,根据你的说法,调用者会知道处理它。无需回调。

    以实例状态存储检索到的数据似乎是一种糟糕的方式。相反,返回一个包含该数据的对象。这会产生更直接的 API 并且具有更少的可变状态。


            finally
            {
                reader.Close();
                _connection.Close();
                _connection.Dispose();
            }
    

    有一个更好的方法来解决这个问题:将资源包装在 using 语句中。尤其是与迷信的双重处置模式分道扬镳。

    【讨论】:

    • 调用环境如何返回异常?
    • 你想说不要使用 try catch,结果异常会冒泡到调用环境,我们应该使用 try/catch 来抓取错误?我理解正确吗?
    • 是的,这是一种非常常见的方法。
    • 这将是冒泡调用环境异常的好方法吗?
    【解决方案2】:

    让调用者处理异常,确保您记录一个体面的错误消息(显示所有相关字段)。 Status 类会惹恼支持人员,因为它吞噬了堆栈跟踪,并且对导致错误的数据只字未提。数据库异常通常是由格式错误的数据引起的,因此在出现问题时记录这些数据很重要。

    顺便说一句,您的 PopulateRecord 和 GetDataCount 方法应该是抽象的,因为基本版本什么都不做。另一个开发人员很容易认为他们不需要实现这些方法,并且会留下一个带有无用 PopulateRecord 和 GetDataCount 方法的类。

    【讨论】:

    • 你能发布一些你所说的代码吗?只是不明白你试图指出什么。
    • 你可以尝试类似:catch (Exception ex) { _logger.ErrorFormat(“SQL command ‘{0)’ failed.例外:{1}”,command.CommandText,例如); // 你需要注入一个 _logger throw; // 调用者仍然需要处理异常但是你已经记录了相关数据 }
    • 你介意发布你所说的代码吗......不太清楚你想说什么。谢谢
    • 这不清楚你想说什么“你需要注入一个 _logger 抛出;”
    • catch (Exception ex) { _logger.ErrorFormat(“SQL command ‘{0)’ failed. Exception: {1}”, command.CommandText, ex); throw; }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多