我正在检索适量的数据并对其进行处理 - 没有什么独特的。起初奇怪的是,对于某些数据集,它工作得很好,而对于其他数据集,我收到以下错误消息:
![enter image description here](https://i.stack.imgur.com/0ymMV.png)
不过,这个错误消息似乎完全是胡言乱语(无论如何都是误导性的),因为失败集的数据并不比成功集的数据多,所以运行“坏”数据不应该花费更长的时间比好的。
也许更具有启发性的是之后出现的其他错误消息:
![enter image description here](https://i.stack.imgur.com/7JJN5.png)
![enter image description here](https://i.stack.imgur.com/9lK6R.png)
注意:我得到这些详细的错误对话框,而不是更简洁的对话框,因为您可以在下面代码的 catch 块中看到调试代码。
因此,显然这并不是真正的“数据太多”问题,正如最初的错误消息所表明的那样。这也不是一个“缺失数据”问题,因为如果我查询 2014 年 12 月到 2015 年 12 月的数据(下个月没有数据),它运行得很好——它只返回 2015 年 12 月的全 0;所以这一定是一个“坏(不仅仅是丢失)数据”的问题。我如何确定什么是坏数据并防御性地防止它破坏应用程序的运行?
上面的 err 消息中涉及的第 601 行包含以下代码:
private void ReadData(string _unit, string monthBegin, string monthEnd, string beginYear, string endYear)
{
try
{
String dateBegin = UsageRptConstsAndUtils.GetYYYYMMDD(monthBegin, beginYear, true);
String dateEnd = UsageRptConstsAndUtils.GetYYYYMMDD(monthEnd, endYear, false);
DateTime dtBegin = UsageRptConstsAndUtils.DatifyYYYYMMDD(dateBegin);
DateTime dtEnd = UsageRptConstsAndUtils.DatifyYYYYMMDD(dateEnd);
DataTable dtUsage = SqlDBHelper.ExecuteDataSet("sp_ViewProductUsage_MappingRS", CommandType.StoredProcedure,
new SqlParameter() { ParameterName = "@Unit", SqlDbType = SqlDbType.VarChar, Value = _unit },
new SqlParameter() { ParameterName = "@BegDate", SqlDbType = SqlDbType.DateTime, Value = dtBegin },
new SqlParameter() { ParameterName = "@EndDate", SqlDbType = SqlDbType.DateTime, Value = dtEnd }
);
SqlDBHelper.ExecuteDataSet() 是:
public static DataTable ExecuteDataSet(string sql, CommandType cmdType, params SqlParameter[] parameters)
{
using (DataSet ds = new DataSet())
using (SqlConnection connStr = new SqlConnection(UsageRptConstsAndUtils.CPSConnStr))
using (SqlCommand cmd = new SqlCommand(sql, connStr))
{
cmd.CommandType = cmdType;
foreach (var item in parameters)
{
cmd.Parameters.Add(item);
}
try
{
cmd.Connection.Open();
new SqlDataAdapter(cmd).Fill(ds);
}
catch (SqlException sqlex)
{
for (int i = 0; i < sqlex.Errors.Count; i++)
{
var sqlexDetail = String.Format("From ExecuteDataSet(), SQL Exception #{0}{1}Source: {2}{1}Number: {3}{1}State: {4}{1}Class: {5}{1}Server: {6}{1}Message: {7}{1}Procedure: {8}{1}LineNumber: {9}",
i + 1, // Users would get the fantods if they saw #0
Environment.NewLine,
sqlex.Errors[i].Source,
sqlex.Errors[i].Number,
sqlex.Errors[i].State,
sqlex.Errors[i].Class,
sqlex.Errors[i].Server,
sqlex.Errors[i].Message,
sqlex.Errors[i].Procedure,
sqlex.Errors[i].LineNumber);
MessageBox.Show(sqlexDetail);
}
}
catch (Exception ex)
{
String exDetail = String.Format(UsageRptConstsAndUtils.ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
MessageBox.Show(exDetail);
}
return ds.Tables[0];
}
}
第 396 行(在最后一个错误消息中引用)是这里的第一行代码:
private String GetContractedItemsTotal()
{
var allContractRecords = _itemsForMonthYearList.Where(x => x.ContractItem);
var totalContractItemPurchases = allContractRecords.Sum(x => x.TotalPurchases);
return totalContractItemPurchases.ToString("C");
}
什么可能导致此代码有时崩溃并出现“找不到表 0”和“值不能为空”异常?或者更重要的是,当值为空时,如何防止它造成如此严重的破坏?
更多背景信息:
_itemsForMonthYearList 定义如下:
private List<ItemsForMonthYear> _itemsForMonthYearList;
..并像这样填充:
var ifmy = new ItemsForMonthYear();
int qty = Convert.ToInt32(productUsageByMonthDataRow["TotalQty"]);
// TotalPrice as Decimal for calculation
Decimal totPrice = Convert.ToDecimal(productUsageByMonthDataRow["TotalPrice"]);
Decimal avgPrice = Convert.ToDecimal(productUsageByMonthDataRow["AvgPrice"]);
String monthYear = productUsageByMonthDataRow["MonthYr"].ToString();
ifmy.ItemDescription = desc;
ifmy.TotalPackages = qty;
ifmy.TotalPurchases = totPrice;
ifmy.AveragePrice = avgPrice;
ifmy.monthYr = monthYear;
ifmy.ContractItem = contractItem; // added 11/16/2016
if (null == _itemsForMonthYearList)
{
_itemsForMonthYearList = new List<ItemsForMonthYear>();
}
_itemsForMonthYearList.Add(ifmy);