如何使用OLeDB查询正确填充DataTable

时间:2016-03-08 12:41:45

标签: c# datatable

编辑2请阅读 :这是一个非常特定的问题,因为代码运行正常,它只是没有按照我希望的方式工作。在发布答案或评论之前,请仔细阅读并确保您了解我需要帮助的地方。非常感谢。

我是新手程序员/编码员。我正在尝试从所有员工假期的访问数据库表填充 DataTable ,其中包含所选员工假期的详细信息。目前,使用查询,我的代码计算数据库的[假日]表中有多少假期,这些假期具有所选员工的PayrollNo。从那里,它在程序中的 DataTable 中填充新行,其中第一个假期与相关的PayrollNo 按员工的假期数量。

例如:Ben有 3个假期,但该表格将在 3 行填充第一个假日。

这表明该计划正确计算了他的假期,但我在选择每个员工的假期方面做错了。

它还显示它以我想要的格式写入表格。

我希望能做的事情看起来很简单;让表格填满Ben的所有3个假期,而不仅仅是他的第一个假期。

以下是我的代码部分,其中迭代了所选员工在[Holiday]中假期数量的循环。

DataTable dt = new DataTable(); //Creates Table
dt.Clear();

dt.Columns.Add("Hol/Abs", typeof(string));      // Column 0  
dt.Columns.Add("FirstDay", typeof(DateTime));   // Column 1 
dt.Columns.Add("LastDay", typeof(DateTime));    // Column 2
dt.Columns.Add("TotalDays", typeof(int));       // Column 3
dt.Columns.Add("Reason", typeof(string));       // Column 4

LblName.Text = PassName; //Loads Name

string ConnString = @"Provider = Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\\HoliPlanData.accdb;Persist Security Info=False";

string Query = "SELECT PayrollNo FROM [Employee] WHERE (FirstName + ' ' + LastName) = @Name"; //Will supply selected Employee's PayrollNo

string CountHolQuery = "SELECT COUNT(*) FROM [Holiday] WHERE PayrollNo = @PayrollNo"; //Will count all of that Employee's Holidays
string CountAbsQuery = "SELECT COUNT(*) FROM [Absences] WHERE PayrollNo = @PayrollNo"; //Will count all of that Employee's Absences
string GetStartQuery = "SELECT StartDate FROM [Holiday] WHERE PayrollNo = @PayrollNo"; // Will select the start date of Holidays
string GetEndQuery = "SELECT EndDate FROM [Holiday] WHERE PayrollNo = @PayrollNo"; // Will select the start date of Absences
string GetReasonQuery = "SELECT Reason FROM [Holiday] WHERE PayrollNo = @PayrollNo";
string AbsGetStartQuery = "SELECT StartDate FROM [Absences] WHERE PayrollNo = @PayrollNo";
string AbsGetEndQuery = "SELECT EndDate FROM [Absences] WHERE PayrollNo = @PayrollNo";
string AbsGetReasonQuery = "SELECT Comments FROM [Absences] WHERE PayrollNo = @PayrollNo";

using (OleDbConnection conn = new OleDbConnection(ConnString))
using (OleDbCommand GetPayroll = new OleDbCommand(Query, conn))            
{
    conn.Open();                
    GetPayroll.Parameters.Add("@Name", OleDbType.VarChar).Value = LblName.Text;
    int GotPayroll = Convert.ToInt32(GetPayroll.ExecuteScalar());   //Uses Query to Get PayrollNo
    OleDbCommand CountRowsInHol = new OleDbCommand(CountHolQuery, conn);
    OleDbCommand CountRowsInAbs = new OleDbCommand(CountAbsQuery, conn);
    CountRowsInHol.Parameters.AddWithValue("@PayrollNo", OleDbType.Integer).Value = GotPayroll;
    CountRowsInAbs.Parameters.AddWithValue("@PayrollNo", OleDbType.Integer).Value = GotPayroll;
    int HolidayCount = (int) (CountRowsInHol.ExecuteScalar()); //Uses CountHolQuery to Get HowMany lines are in [Holiday] 
    int AbsenceCount = (int)(CountRowsInAbs.ExecuteScalar()); //Uses CountAbsQuery to Get HowMany lines are in [Absences] 
    int HolLoopCount = 1;

    while (HolLoopCount <= HolidayCount) //Will go though all SelectedPayroll's holidays' in [Holiday]
    {                                        
        OleDbCommand GetStart = new OleDbCommand(GetStartQuery, conn);
        OleDbCommand GetEnd = new OleDbCommand(GetEndQuery, conn);
        OleDbCommand GetReason = new OleDbCommand(GetReasonQuery, conn);
        GetStart.Parameters.Add("@PayrollNo", OleDbType.Integer).Value = GotPayroll;                    
        GetEnd.Parameters.Add("@PayrollNo", OleDbType.Integer).Value = GotPayroll;
        GetReason.Parameters.Add("@PayrollNo", OleDbType.Integer).Value = GotPayroll;
        DateTime StartHold = Convert.ToDateTime(GetStart.ExecuteScalar());
        DateTime EndHold = Convert.ToDateTime(GetEnd.ExecuteScalar());
        string ReasonHold = (GetReason.ExecuteScalar()).ToString();
        DataRow NewLine = dt.NewRow();
        NewLine["Hol/Abs"] = "Holiday";
        NewLine["FirstDay"] = StartHold;
        NewLine["LastDay"] = EndHold;
        NewLine["TotalDays"] = GetNoWeekends(StartHold,EndHold);
        NewLine["Reason"] = ReasonHold;
        dt.Rows.Add(NewLine);
        HolLoopCount = HolLoopCount + 1;
    }

    dataGridView1.DataSource = dt;
    dataGridView1.Refresh();
}

我的假设是我必须通过[Holiday] Datatable本身迭代,或者在代码中创建另一个DataTable来存储所有相关行,然后从那里提取显​​示表的详细信息。 任何帮助或建议将不胜感激。

修改

我添加了剩余的代码来显示查询和进程。还要说明我如何填补表格,尽管概述了这不是问题发生的原因。

2 个答案:

答案 0 :(得分:1)

要从MS Access数据库获取DataTable,请使用以下示例代码段:

列表 1.使用DataTable对象lib从MS Access获取OleDb

private DataTable GetDataTable(string strCN, string strSQL)
{
    try
    {
        using (OleDbConnection _conn = new OleDbConnection(strCN))
        {
            using (OleDbCommand _command = new OleDbCommand())
            {
                _command.CommandType = CommandType.Text;
                _command.Connection = _conn;
                _command.CommandText = strSQL;
                _conn.Open();

                using (OleDbDataReader _dr = _command.ExecuteReader())
                {
                    DataTable _dt = new DataTable();
                    _dt.Load(_dr);
                    return _dt;
                }
            }
        }
    }
    catch
    {
        throw;
    }
}

其中strCN是连接字符串,strSQL是您的SELECT查询。您可以调用此方法并将各种SQL查询作为参数传递。

与您的情况相关,它看起来不像正确的SQL SELECT查询来完成这项工作。如果您确实需要获取DataTable然后将其绑定到数据感知控件(如GridView),那么您应该使用上面提供的方法。如果只需要获得标量值,请使用清单2中的以下方法。

清单2. 使用OleDb对象lib从MS Access获取标量值

/// <summary>
/// Read DB Read Scalar on SQL command input
/// </summary>
/// <param name="SQL">string</param>
/// <returns>string</returns>
private static string ReadScalar(string ConnString, string SQL)
{
    string _ret;
    try
    {
        using (OleDbConnection _conn = new OleDbConnection(ConnString))
        {
            using (OleDbCommand _command = new OleDbCommand(SQL, _conn))
            {
                _command.CommandType = CommandType.Text;
                _conn.Open();
                _ret = _command.ExecuteScalar().ToString();
            }
            return _ret;
        }
    }
    catch { return null; }
}

希望这会有所帮助。

答案 1 :(得分:1)

首先对您的代码进行轻微(不完整)修订:

  string ConnString = @"Provider = Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\\HoliPlanData.accdb;Persist Security Info=False";
  string Query = "SELECT PayrollNo FROM [Employee] WHERE (FirstName + ' ' + LastName) = @Name"; //Will supply selected Employee's PayrollNo

  string getHolidayQuery = @"SELECT StartDate, EndDate, Reason 
     FROM [Holiday] 
     WHERE PayrollNo = @PayrollNo"; // Will select data from Holidays

  string getAbsencesQuery = @"SELECT StartDate, EndDate, Comments 
     FROM [Absences] 
     WHERE PayrollNo = @PayrollNo";

  var holidayData = new DataTable();
  var absenceData = new DataTable();

  using (OleDbConnection conn = new OleDbConnection(ConnString))
  {
    var getPayroll = new OleDbCommand(Query, conn);
    getPayroll.Parameters.AddWithValue("@name", LblName.Text);

    var holidaysQuery = new OleDbCommand(getHolidayQuery, conn);
    var absencesQuery = new OleDbCommand(getAbsencesQuery, conn);
    conn.Open();

    int GotPayroll = Convert.ToInt32(getPayroll.ExecuteScalar());   //Uses Query to Get PayrollNo
    holidaysQuery.Parameters.AddWithValue("@PayrollNo", GotPayroll);
    absencesQuery.Parameters.AddWithValue("@PayrollNo", GotPayroll);

    holidayData.Load(holidaysQuery.ExecuteReader());
    absenceData.Load(absencesQuery.ExecuteReader());

    conn.Close();
  }

foreach (DataRow row in holidayData.AsEnumerable())
{
    // here you could craft a new data table
    // however there is a discrepancy. 
    // How would the data in Holiday would relate to those
    // in absences. With the relation known, we might have 
    // gotten a single datatable from the database.
    // Probably you should give data samples.


    //    DateTime StartHold = Convert.ToDateTime(GetStart.ExecuteScalar());
    //    DateTime EndHold = Convert.ToDateTime(GetEnd.ExecuteScalar());
    //    string ReasonHold = (GetReason.ExecuteScalar()).ToString();

    // Above lines are sort of saying:
    //    DateTime StartHold = (DateTime)row["StartDate"];
    //    DateTime EndHold = (DateTime)row["EndDate"];
    //    string ReasonHold = (string)row["Reason"];
    // without roundtripping to database per field

  }
//...

基本上,我的意思是,不是每个字段执行一个标量,而是对数据库进行一次调用。使用标量方法,查询中没有任何内容可以区分&#34;首先&#34;从第二个或第三个排。 ie:对于payrollNo 5,假设有3个假期条目:

5, Jan 22, 2016, Jan 26, 2016
5, Feb 1, 2016, Feb 5, 2016
5, Feb 22, 2016, Feb 26, 2016

使用您的查询,只使用PayrollNo作为标准,您将始终从第一行(2016年1月22日,例如startDate)获取值。

首先将此数据放入本地数据表中,至少提供可迭代的结构。

从这个数据或直接从源数据创建一个数据表,使用Linq就像我最初说的一样容易(Linq它是IQueryable而不是DataTable,但也可以用DataTable)。 Linq是C#本身的一部分:)意味着语言集成查询 - IOW查询语言内置于C#本身。这是一个Linq代码,用于查询示例Northwind中的一些数据(使用来自codeplex的IQToolkit) - 这是您需要的所有代码,包括Form和DataGridView:

void Main()
{
  string path   = @"D:\data\Northwind.accdb";
  string conStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="+path;

  var provider= new AccessQueryProvider(new OleDbConnection(conStr), 
                    new ImplicitMapping(), QueryPolicy.Default);

  var sampleOrders = provider.GetTable<Order>("Orders")
                  .Where (o => o.OrderDate == new DateTime(1997,1,1));

  Form f = new Form{Height=800,Width=1024};
  DataGridView dgv = new DataGridView { Dock=DockStyle.Fill };
  dgv.DataSource = sampleOrders.ToList();

  f.Controls.Add(dgv);
  f.Show();
}

// Entity Class
public class Order {
 public int OrderID { get; set; }
 public string CustomerID { get; set; }
 public int EmployeeID { get; set; }
 public DateTime OrderDate { get; set; }
 public DateTime? RequiredDate { get; set; }
 public DateTime? ShippedDate { get; set; }
 public int ShipVia { get; set; }
 public decimal? Freight { get; set; }
 public string ShipCity { get; set; }
 public string ShipCountry { get; set; }
}