Sql DataReader 有行但 Returns 有空数据
Sql DataReader Has Rows but Returns With Empty data
我正在对 sql 数据库中的 select 数据进行查询。它有行,但数据 raader.Read()
函数 returns false
并且行是空的,因为我在调试
中检查过
我一直在使用的代码是
public void getSale()
{
DB db = new DB();
try
{
db.cmd.CommandText = "select * from Sale where date is not null and (date between '"+StartDate+"' and '"+EndDate+"') order by date";
db.cmd.Connection = db.con;
db.con.Open();
if(db.con.State == System.Data.ConnectionState.Open)
{
db.dataReader = db.cmd.ExecuteReader();
if(db.dataReader.HasRows)
{
while(db.dataReader.Read())
{
SaleModel sm = new SaleModel();
sm.SaleId = long.Parse(db.dataReader["Id"].ToString());
sm.UserName = db.dataReader["UserName"].ToString();
sm.ItemsQuantity = int.Parse(db.dataReader["ItemsQuantity"].ToString());
sm.TotalAmount = double.Parse(db.dataReader["TotalAmount"].ToString());
sm.SubTotal = double.Parse(db.dataReader["SubTotal"].ToString());
sm.Discount = double.Parse(db.dataReader["Discount"].ToString());
sm.Completed = bool.Parse(db.dataReader["Completed"].ToString());
sm.Date = DateTime.Parse(db.dataReader["Date"].ToString());
sm.CustomerPhone = long.Parse(db.dataReader["CustomerPhone"].ToString());
SalesList.Add(sm);
}
db.con.Close();
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
}
}
当我在查询编辑器上测试此查询时,返回了 Visual studio 行
有没有人可以帮忙?
没有发现任何问题,只是您使用的是 date
,这是一个保留字,而不是您的实际列名。将您的查询更改为
db.cmd.CommandText = "select * from Sale where [date] is not null and ([date] between '"+StartDate+"' and '"+EndDate+"') order by [date]";
为什么要连接字符串来构建 sql 查询?永远不要那样做。它是 sql-injection 的来源,可能会导致这样的问题。而是使用参数化查询。
也不要像 DB
class 那样使用 SqlConnection
包装器。这可能会导致 several other issues。相反,最好使用 using
-statament 在您需要的地方创建、打开、关闭和处置它们。连接池将为您管理其余部分。
public List<SaleModel> GetSale(DateTime startDate, DateTime endDate)
{
string sql = @"select * from Sale
where date is not null
and date between @StartDate and @EndDate
order by date";
var salesList = new List<SaleModel>();
try
{
using (var con = new SqlConnection("insert your connection string"))
using (var cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = startDate;
cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = endDate;
con.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
SaleModel sm = new SaleModel();
sm.SaleId = long.Parse(reader["Id"].ToString());
sm.UserName = reader["UserName"].ToString();
sm.ItemsQuantity = int.Parse(reader["ItemsQuantity"].ToString());
sm.TotalAmount = double.Parse(reader["TotalAmount"].ToString());
sm.SubTotal = double.Parse(reader["SubTotal"].ToString());
sm.Discount = double.Parse(reader["Discount"].ToString());
sm.Completed = bool.Parse(reader["Completed"].ToString());
sm.Date = DateTime.Parse(reader["Date"].ToString());
sm.CustomerPhone = long.Parse(reader["CustomerPhone"].ToString());
salesList.Add(sm);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
}
return salesList;
}
我很确定这行得通(f.e。可能是本地化问题)。
旁注:方法 GetSale
应该 return 一个 List<SaleModel>
而不是填充一个。您还应该将参数作为 DateTime
传递给该方法。我已经在我的代码示例中更改了它。
这是构建代码的好得多的方法,它很有可能也能解决您的问题:
//accept the date values as parameter arguments, return the result.
// Do NOT mess about with variables at the global or class scope.
public IEnumerable<SalesModel> getSale(DateTime StartDate, DateTime EndDate)
{
string sql = "select * from Sale where date is not null and (date between @StartDate and @EndDate) order by date";
//DON'T abstract SqlCommand/SqlConnection. DO abstract your connection string.
//Also, don't bother with the try/catch at this level. You can't really do anything with it here, so worry about the exception in calling code.
using (var cn = new SqlConnection(DB.ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = StartDate
cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = EndDate
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
var sm = new SaleModel();
//If you have good schema design, these values are **already** in the correct type.
// The old code forces an expensive conversion to string, following by an expensive parse back to the type it already had.
// We can do MUCH better.
sm.SaleId = (long)rdr["Id"];
//but it is okay for types that are *already* strings
sm.UserName = rdr["UserName"].ToString();
sm.ItemsQuantity = (int)rdr["ItemsQuantity"];
sm.TotalAmount = (double)rdr["TotalAmount"]);
sm.SubTotal = (double)rdr["SubTotal"];
sm.Discount = (double)rdr["Discount"];
sm.Completed = (bool)rdr["Completed"];
sm.Date = (DateTime)rdr["Date"];
sm.CustomerPhone = (long).rdr["CustomerPhone"];
yield return sm;
}
}
}
}
这里再次没有所有额外的评论。这里的重点是,这仍然比使用字符串连接的原始代码少,并且编写时间不到 10 分钟。好的代码不一定需要更长的时间。
public IEnumerable<SalesModel> getSale(DateTime StartDate, DateTime EndDate)
{
string sql = "select * from Sale where date is not null and (date between @StartDate and @EndDate) order by date";
using (var cn = new SqlConnection(DB.ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = StartDate
cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = EndDate
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
var sm = new SaleModel();
sm.SaleId = (long)rdr["Id"];
sm.UserName = rdr["UserName"].ToString();
sm.ItemsQuantity = (int)rdr["ItemsQuantity"];
sm.TotalAmount = (double)rdr["TotalAmount"]);
sm.SubTotal = (double)rdr["SubTotal"];
sm.Discount = (double)rdr["Discount"];
sm.Completed = (bool)rdr["Completed"];
sm.Date = (DateTime)rdr["Date"];
sm.CustomerPhone = (long).rdr["CustomerPhone"];
yield return sm;
}
}
}
}
请注意,我 return 一个 IEnumerable 而不是一个列表。如果您真的 需要一个列表(提示:您可能不需要,坚持使用 IEnumerable 会更快),您可以只对结果调用 ToList()。
我正在对 sql 数据库中的 select 数据进行查询。它有行,但数据 raader.Read()
函数 returns false
并且行是空的,因为我在调试
我一直在使用的代码是
public void getSale()
{
DB db = new DB();
try
{
db.cmd.CommandText = "select * from Sale where date is not null and (date between '"+StartDate+"' and '"+EndDate+"') order by date";
db.cmd.Connection = db.con;
db.con.Open();
if(db.con.State == System.Data.ConnectionState.Open)
{
db.dataReader = db.cmd.ExecuteReader();
if(db.dataReader.HasRows)
{
while(db.dataReader.Read())
{
SaleModel sm = new SaleModel();
sm.SaleId = long.Parse(db.dataReader["Id"].ToString());
sm.UserName = db.dataReader["UserName"].ToString();
sm.ItemsQuantity = int.Parse(db.dataReader["ItemsQuantity"].ToString());
sm.TotalAmount = double.Parse(db.dataReader["TotalAmount"].ToString());
sm.SubTotal = double.Parse(db.dataReader["SubTotal"].ToString());
sm.Discount = double.Parse(db.dataReader["Discount"].ToString());
sm.Completed = bool.Parse(db.dataReader["Completed"].ToString());
sm.Date = DateTime.Parse(db.dataReader["Date"].ToString());
sm.CustomerPhone = long.Parse(db.dataReader["CustomerPhone"].ToString());
SalesList.Add(sm);
}
db.con.Close();
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
}
}
当我在查询编辑器上测试此查询时,返回了 Visual studio 行
有没有人可以帮忙?
没有发现任何问题,只是您使用的是 date
,这是一个保留字,而不是您的实际列名。将您的查询更改为
db.cmd.CommandText = "select * from Sale where [date] is not null and ([date] between '"+StartDate+"' and '"+EndDate+"') order by [date]";
为什么要连接字符串来构建 sql 查询?永远不要那样做。它是 sql-injection 的来源,可能会导致这样的问题。而是使用参数化查询。
也不要像 DB
class 那样使用 SqlConnection
包装器。这可能会导致 several other issues。相反,最好使用 using
-statament 在您需要的地方创建、打开、关闭和处置它们。连接池将为您管理其余部分。
public List<SaleModel> GetSale(DateTime startDate, DateTime endDate)
{
string sql = @"select * from Sale
where date is not null
and date between @StartDate and @EndDate
order by date";
var salesList = new List<SaleModel>();
try
{
using (var con = new SqlConnection("insert your connection string"))
using (var cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = startDate;
cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = endDate;
con.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
SaleModel sm = new SaleModel();
sm.SaleId = long.Parse(reader["Id"].ToString());
sm.UserName = reader["UserName"].ToString();
sm.ItemsQuantity = int.Parse(reader["ItemsQuantity"].ToString());
sm.TotalAmount = double.Parse(reader["TotalAmount"].ToString());
sm.SubTotal = double.Parse(reader["SubTotal"].ToString());
sm.Discount = double.Parse(reader["Discount"].ToString());
sm.Completed = bool.Parse(reader["Completed"].ToString());
sm.Date = DateTime.Parse(reader["Date"].ToString());
sm.CustomerPhone = long.Parse(reader["CustomerPhone"].ToString());
salesList.Add(sm);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
}
return salesList;
}
我很确定这行得通(f.e。可能是本地化问题)。
旁注:方法 GetSale
应该 return 一个 List<SaleModel>
而不是填充一个。您还应该将参数作为 DateTime
传递给该方法。我已经在我的代码示例中更改了它。
这是构建代码的好得多的方法,它很有可能也能解决您的问题:
//accept the date values as parameter arguments, return the result.
// Do NOT mess about with variables at the global or class scope.
public IEnumerable<SalesModel> getSale(DateTime StartDate, DateTime EndDate)
{
string sql = "select * from Sale where date is not null and (date between @StartDate and @EndDate) order by date";
//DON'T abstract SqlCommand/SqlConnection. DO abstract your connection string.
//Also, don't bother with the try/catch at this level. You can't really do anything with it here, so worry about the exception in calling code.
using (var cn = new SqlConnection(DB.ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = StartDate
cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = EndDate
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
var sm = new SaleModel();
//If you have good schema design, these values are **already** in the correct type.
// The old code forces an expensive conversion to string, following by an expensive parse back to the type it already had.
// We can do MUCH better.
sm.SaleId = (long)rdr["Id"];
//but it is okay for types that are *already* strings
sm.UserName = rdr["UserName"].ToString();
sm.ItemsQuantity = (int)rdr["ItemsQuantity"];
sm.TotalAmount = (double)rdr["TotalAmount"]);
sm.SubTotal = (double)rdr["SubTotal"];
sm.Discount = (double)rdr["Discount"];
sm.Completed = (bool)rdr["Completed"];
sm.Date = (DateTime)rdr["Date"];
sm.CustomerPhone = (long).rdr["CustomerPhone"];
yield return sm;
}
}
}
}
这里再次没有所有额外的评论。这里的重点是,这仍然比使用字符串连接的原始代码少,并且编写时间不到 10 分钟。好的代码不一定需要更长的时间。
public IEnumerable<SalesModel> getSale(DateTime StartDate, DateTime EndDate)
{
string sql = "select * from Sale where date is not null and (date between @StartDate and @EndDate) order by date";
using (var cn = new SqlConnection(DB.ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = StartDate
cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = EndDate
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
var sm = new SaleModel();
sm.SaleId = (long)rdr["Id"];
sm.UserName = rdr["UserName"].ToString();
sm.ItemsQuantity = (int)rdr["ItemsQuantity"];
sm.TotalAmount = (double)rdr["TotalAmount"]);
sm.SubTotal = (double)rdr["SubTotal"];
sm.Discount = (double)rdr["Discount"];
sm.Completed = (bool)rdr["Completed"];
sm.Date = (DateTime)rdr["Date"];
sm.CustomerPhone = (long).rdr["CustomerPhone"];
yield return sm;
}
}
}
}
请注意,我 return 一个 IEnumerable 而不是一个列表。如果您真的 需要一个列表(提示:您可能不需要,坚持使用 IEnumerable 会更快),您可以只对结果调用 ToList()。