【问题标题】:How to load data from sql query to datagridview?如何将数据从 sql 查询加载到 datagridview?
【发布时间】:2019-07-19 06:54:32
【问题描述】:

我已经声明了 2 个字符串变量:

string fname;
string lname;

当我在 phpMyAdmin 数据库中编写 MySQL 查询时:

SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN
project1.order_status ON workers.ID_WORKER = order_status.ID_WORKER 
INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER 
WHERE orders.ORDER_NUMBER = 'TEST' GROUP BY workers.FNAME, workers.LNAME

我有 2 个唤醒者:

-“亚当盖克斯”和

“安德鲁蠕虫”

然后我想存储这个查询中的对象并将该数据加载到 datagridview:

    string query1 = string.Format("SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " +
    "ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " +
    "WHERE orders.ORDER_NUMBER = '"+ NrOrder +"' GROUP BY workers.FNAME, workers.LNAME");

    SQLdata.connection.Open();
    using (var command = new MySqlCommand(query1, SQLdata.connection))
    {
        using (var reader1 = command.ExecuteReader())
        {
            while (reader1.Read())
            {
                fname = Convert.ToString(reader1[0]);
                lname = Convert.ToString(reader1[1]);
            }
        }
    }

我在 while 循环中的代码行中设置了断点,并读取了所有 FNAME 和 LNAME。然后它正确加载所有数据。接下来我想将它们加载到datagridview。

        SQLdata.connection.Close();
        sick_leaves x = new sick_leaves();
        x.FNAME = fname;
        x.LNAME = lname;
        return x;     

并像这样绑定它们:

        sick_leaves a = calculate_sickness_leaves(txt_NrOrder.Text);

        cu = calculate_sickness_leaves(txt_NrOrder.Text);
        var source = new BindingSource();
        source.DataSource = cu;
        dataGridView2.DataSource = source;

然后使用 Orders.cs 文件中的数据:

public class sick_leaves
{
    public string FNAME { get; set; }
    public string LNAME { get; set; }
}

在 datagridview 中编译后,我只加载了 1 个 Worker:“Andrew Worm”。那应该是2个worker,所以它没有从sql查询中加载所有数据。

现在:如何将所有数据从 sql 查询加载到 datagridview?有任何想法吗? 警告!我需要桌面应用程序方面的帮助

编辑

我想通过保存代码结构来加载该数据,因为我想通过计算疾病、离开时间来构建该 datagridview。 (带有TimeSpan 对象)。可以这样写吗?

我的代码:

GenerateOrder.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MySql.Data.MySqlClient;
using System.Windows.Forms.DataVisualization.Charting;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
using System.Diagnostics;

namespace ControlDataBase
{
    public partial class GenerateChartsOfOrders : Form
    {
        string fname;
        string lname;
        sick_leaves cu = new sick_leaves();
        public GenerateChartsOfOrders()
        {
            InitializeComponent();
        }        

        public void loaddata2()
        {
            string connect = "datasource=localhost;port=3306;username=root;password=";

            MySqlConnection connection = new MySqlConnection(connect);
            connection.Open();

            sick_leaves a = calculate_sickness_leaves(txt_NrOrder.Text);

            cu = calculate_sickness_leaves(txt_NrOrder.Text);
            var source = new BindingSource();
            source.DataSource = cu;
            dataGridView2.DataSource = source;

            connection.Close();
        }

        private sick_leaves calculate_sickness_leaves(string NrOrder)
        {
            string query1 = string.Format("SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " +
            "ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " +
            "WHERE orders.ORDER_NUMBER = '"+ NrOrder +"' GROUP BY workers.FNAME, workers.LNAME");

            SQLdata.connection.Open();
            using (var command = new MySqlCommand(query1, SQLdata.connection))
            {
                using (var reader1 = command.ExecuteReader())
                {
                    while (reader1.Read())
                    {
                        fname = Convert.ToString(reader1[0]);
                        lname = Convert.ToString(reader1[1]);
                    }
                }
            }

            SQLdata.connection.Close();
            sick_leaves x = new sick_leaves();
            x.FNAME = fname;
            x.LNAME = lname;
            return x;         
        }
    }
}

Orders.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

    namespace ControlDataBase
    {
        public class sick_leaves
        {
            public string FNAME { get; set; }
            public string LNAME { get; set; }
        }
    }

SQLData.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql;
using MySql.Data.MySqlClient;

namespace ControlDataBase
{
    class SQLdata
    {
        public static MySqlConnection connection = new MySqlConnection
        ("datasource=localhost;port=3306;username=root;password=");
    }
}

【问题讨论】:

  • 您可以在 .NET 中使用 ObjectDataSource 并将其绑定到 ASPxGridView
  • @Syafiqur__ 我可以在 .NET 中使用,但我需要桌面应用程序的帮助。
  • 代码有几个问题: 1. 你定义了fnamelname 作为表单域。 2. 在calculate_sickness_leaves 中,您在while(reader1.Read()) 中设置这些字段的值 3. 最后从calculate_sickness_leaves 返回一个sick_leaves 对象。 → 所以基本上,fnamelname 将始终包含表最后一行的名字和姓氏,因为 1 和 2。你的 DataGridView 将始终显示一条记录,因为 3。跨度>

标签: c# mysql .net winforms datagridview


【解决方案1】:

代码有几个问题:

  1. 您已将fnamelname 定义为表单字段。
  2. calculate_sickness_leaves 中您在while(reader1.Read()) 中设置了这些字段的值
  3. 最后从calculate_sickness_leaves返回一个sick_leaves对象。

所以基本上,fnamelname 将始终包含表格最后一行的名字和姓氏,因为 1 和 2。

您的 DataGridView 将始终显示一条记录,因为 3。

解决问题:

  1. 删除不需要的 fnamelname
  2. calculate_sickness_leaves的输出类型更改为IEnumerable<sick_leaves>
  3. 在while循环中,当从数据读取器中读取字段值时,创建一个sick_leavesyield return的新实例。

旁注

  • 始终使用参数化查询来防止 SQL 注入。
  • 在处理连接等一次性对象时,请始终使用using 语句。
  • 如果您对使用类型化实体对象感兴趣,那么您可能需要查看MySQL Connector 以获取Entity Framework

示例

您可以找到很多关于将数据加载到DataTable 或使用DataReader 的示例。无论如何,我将在这里再分享两个示例,向您展示如何从 MySql 获取数据并转换为特定类型的列表。

在以下示例中,我假设您有一个这样的 Employee 类:

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

示例 1 - 使用 DataAdapter、DataTable 和 Select 扩展方法

public IEnumerable<Employee> GetEmployees()
{
    string connectionString = "CONNECTION STRING";
    string commandText = "COMMAND TEXT";
    DataTable table = new DataTable();
    using (var adapter = new MySqlDataAdapter(commandText , connectionString))
        adapter.Fill(table);
    return table.AsEnumerable().Select(x => new Employee()
    {
        FirstName = x.Field<string>("FirstName"),
        LastName = x.Field<string>("LastName")
    });
}

示例 2 - 使用 DataReader 和 yield return new Employee

public IEnumerable<Employee> GetEmployees()
{
    string connectionString = "CONNECTION STRING";
    string commandText = "COMMAND TEXT";
    using (var connection = new MySqlConnection(connectionString))
    {
        connection.Open();
        using (var command = new MySqlCommand(commandText, connection))
        {
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    yield return new Employee()
                    {
                        FirstName = reader.GetFieldValue<string>(0),
                        LastName = reader.GetFieldValue<string>(1)
                    };
                }
            }
        }
    }
}

您可以像这样使用上述任何一种方法:

bindingSource.DataSource = GetEmployees();
dataGridView.DataSource = bindingSource;

【讨论】:

  • @Syafiqur__ 是的,您可以使用 OleDb 对象,如 OleDbConnectionOleDbCommand 从 Excel 表中获取数据。看看this post
  • 是的。但我总是收到错误Microsoft.ACE.OLEDB.12.0............ 尽管我有那个 oledb
  • @Syafiqur__ 看看this post。 (可能是x86/x64位数的原因)
【解决方案2】:

这可能会有所帮助

private void GetData(string selectCommand)
    {
        try
        {
            // Specify a connection string.  
            // Replace <SQL Server> with the SQL Server for your Northwind sample database.
            // Replace "Integrated Security=True" with user login information if necessary.
            String connectionString =
                "Data Source=<SQL Server>;Initial Catalog=Northwind;" +
                "Integrated Security=True";

            // Create a new data adapter based on the specified query.
            dataAdapter = new SqlDataAdapter(selectCommand, connectionString);

            // Create a command builder to generate SQL update, insert, and
            // delete commands based on selectCommand. 
            SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter);

            // Populate a new data table and bind it to the BindingSource.
            DataTable table = new DataTable
            {
                Locale = CultureInfo.InvariantCulture
            };
            dataAdapter.Fill(table);
            bindingSource1.DataSource = table;

            // Resize the DataGridView columns to fit the newly loaded content.
            dataGridView1.AutoResizeColumns(
                DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
        }
        catch (SqlException)
        {
            MessageBox.Show("To run this example, replace the value of the " +
                "connectionString variable with a connection string that is " +
                "valid for your system.");
        }
    }

【讨论】:

    【解决方案3】:

    C# 数据访问层(本例中 DAl.cs 中只有 1 个 sub 的简化示例):

    Using System.Data.SqlClient;
    
    Public Class DAL
    {
        Public Static void GetQueryResults(String cmdText)
        {
            SqlConnection oConn = New SqlConnection();
            oConn.ConnectionString = MainW.MyConnection;  // get connection string
            SqlCommand cmd = New SqlCommand(cmdText, oConn);
            DataSet ds = New DataSet();
            SqlDataAdapter da = New SqlDataAdapter(cmd);
    
            Try
            {
                oConn.Open();
                da.Fill(ds);       // retrive data
                oConn.Close();
            }
            Catch (Exception ex)
            {
                SysErrScreen errform = New SysErrScreen();
                errform.ChybaText.Text = ex.Message + Constants.vbCrLf + Constants.vbCrLf + cmdText;
                errform.ShowDialog();
                oConn.Close();
            }
    
            Return ds;
        }
    }
    

    在 VB.NET 中相同:

    Imports System.Data.SqlClient
    
    Public Class DAL
    
    Public Shared Function GetQueryResults(cmdText As String)
        Dim oConn As New SqlConnection
        oConn.ConnectionString = MainW.MyConnection  ' get connection string
        Dim cmd As New SqlCommand(cmdText, oConn)
        Dim ds As New DataSet()
        Dim da As New SqlDataAdapter(cmd)
    
        Try
            oConn.Open()
            da.Fill(ds)       ' retrive data
            oConn.Close()
        Catch ex As Exception
            Dim errform As New SysErrScreen
            errform.ChybaText.Text = ex.Message & vbCrLf & vbCrLf & cmdText
            errform.ShowDialog()
            oConn.Close()
        End Try
    
        Return ds
    End Function
    
    End Class
    

    注意,我在别处 (MainW.MyConnection) 定义了一个 ConnectionString,您可以在其中为所有应用程序设置它。您通常会在启动期间从某些设置(文件、应用程序变量)中检索它。

    那我就不好用了(C#):

    Private void FillDGV()
    {
        String cmdText = "SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " + 
    "ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " + 
    "WHERE orders.ORDER_NUMBER = '" + NrOrder + "' GROUP BY workers.FNAME, workers.LNAME\"; ";
            DataSet ds;
            ds = DAL.GetQueryResults(cmdText);
            DataTable dt;
            if (ds.Tables.Count > 0)
            {
                dt = ds.Tables(0);
                this.DataGridView1.DataSource = dt;   // fill DataGridView
            }
        }
    

    VB.NET:

    Private Sub FillDGV()
        Dim cmdText As String = "SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " +
            "ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " +
            "WHERE orders.ORDER_NUMBER = '" & NrOrder & "' GROUP BY workers.FNAME, workers.LNAME""; "
        Dim ds As DataSet
        ds = DAL.GetQueryResults(cmdText)
        Dim dt As DataTable
        If ds.Tables.Count > 0 Then
            dt = ds.Tables(0)
            Me.DataGridView1.DataSource = dt    ' fill DataGridView
        End If
    End Sub
    

    注意,我使用DataTable 作为数据对象,介于DataSetDataGridView 之间。由于多种原因,养成使用它的习惯是件好事(除非使用其他更高级的方法)。一个主要问题是,如果DataSet 表恰好为空,它不会删除您的DataGridView GUI 定义的列。您还可以在 DataTableDataGridView 上更高效、更可靠地执行客户端数据操作。

    也可以考虑,如果他应该使用BindingSource,而不是DataTable。它的实现与 DataTable 非常相似,所以如果你让这个例子正常工作,你可以切换到BindingSource,如果你需要的话。

    另一个考虑是使用参数查询。如果您(您的用户)在封闭的环境中操作您的桌面应用程序,那就没问题了。但是,对于暴露的应用程序,您可以肯定会受到一些 SQL 注入 攻击。

    【讨论】:

    • DataAdapter 将为您打开和关闭连接,因此您无需这样做。
    • @LarsTech 嗯,看起来不错。多年来,我实际上并没有关注这段代码,因为它在单独的类中休息......
    【解决方案4】:

    从 SQL 数据库下载数据并将其呈现在 DataGridView 中时,此代码适用于我:

                string connectionString;
                String sql = "";
                SqlConnection cnn;
    
                sql = "SELECT workers.FNAME, workers.LNAME FROM project1.workers INNER JOIN project1.order_status " +
                "ON workers.ID_WORKER = order_status.ID_WORKER INNER JOIN project1.orders ON orders.ID_ORDER = order_status.ID_ORDER " +
                "WHERE orders.ORDER_NUMBER = '"+ NrOrder +"' GROUP BY workers.FNAME, workers.LNAME"";
                connectionString = @"datasource=localhost;port=3306;username=root;password=";
                cnn = new SqlConnection(connectionString);
                cnn.Open();
                SqlDataAdapter dataadapter = new SqlDataAdapter(sql, cnn);
                DataSet ds = new DataSet();
                dataadapter.Fill(ds, "workers");
                dataGridView1.DataSource = ds;
                dataGridView1.DataMember = "workers";
                cnn.Close();
    

    【讨论】:

    • 好的,但是你把代码放在哪里了?在public void loaddata2()private sick_leaves calculate_sickness_leaves(string NrOrder)
    • @Prochu1991 你的代码结构很复杂。如果您要做的只是呈现来自 DB 的数据而不对其进行任何修改,那么为什么要为它提供两个函数呢?因为您分别为每个人执行此功能,这就是为什么每次您覆盖 dataGridView 并且只显示最后一个人的原因。只需将我的代码放在一个函数中并运行一次,它将下载所有人并在 dataGridView 中显示他们
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多