Вывод данных из БД в DataGridView

131
27 октября 2021, 13:30

не смог найти тему с ответом на мой вопрос. Есть база данных на локальном сервере MySql. Создаю приложение Windows Forms, соединение устанавливается с БД, но данные не выводятся в DataGridView. Точнее выводятся, но пишет System.Collections.Generic.List`1[System.String] за место данных и то только в 1-ом столбце. Не могу понять что это. Подскажите пожалуйста как мне сделать работоспособную программу

Вот код соединения с БД. Метод public List[] Select() создаёт список для вывода.

class DBconnect
    {
        private MySqlConnection connection;
        private string server, database, uid, password;
        public DBconnect()
        {
            Initialize();
        }
        private void Initialize()
        {
            server = "localhost";
            database = "catalog_personal";
            uid = "root";
            password = " ";
            string connectionString;
            connectionString = " SERVER =" + server + " ;" + " DATABASE =" +
            database + " ;" + " UID =" + uid + " ;" + "PASSWORD =" + password + " ;";
            connection = new MySqlConnection(connectionString);
        }
        //Открываем соединение
        private bool OpenConnection()
        {
            try
            {
                connection.Open();
                return true;
            }
            catch(MySqlException ex)
            {
                // При обработке ошибок вы можете основывать ответ вашего приложения
                // по номеру ошибки.
                // Два наиболее распространенных номера ошибок при подключении:
                // 0: не удается подключиться к серверу.
                // 1045: неверное имя пользователя и / или пароль.
                switch(ex.Number)
                {
                    case 0:
                        MessageBox.Show("Невозможно подключиться к серверу, " +
                            "связаться с админ-панелью");
                        break;
                    case 1045:
                        MessageBox.Show("Неверное имя пользователя / пароль, " +
                            "пожалуйста, попробуйте еще раз");
                        break;
                }
                return false;
            }
        }
        //Закрываем соединение
        private bool CloseConnection()
        {
            try
            {
                connection.Close();
                return true;
            }
            catch (MySqlException ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
        }
        public List<string>[] Select()
        {
            string query = " SELECT * FROM personal";
            //Создаем список для сохранения результа вывода
            List<string>[] list = new List<string>[4];
            list[0] = new List<string>();
            list[1] = new List<string>();
            list[2] = new List<string>();
            list[3] = new List<string>();
            //Открываем соединение
            if (this.OpenConnection() == true)
            {
                //Создаем команду
                MySqlCommand cmd = new MySqlCommand(query, connection);
                //Создаем читатель данных и выполняем команду чтения
                MySqlDataReader dataReader = cmd.ExecuteReader();
                while (dataReader.Read())
                {
                    list[0].Add(dataReader[0].ToString());
                    list[1].Add(dataReader[1].ToString());
                    list[2].Add(dataReader[2].ToString());
                    list[3].Add(dataReader[3].ToString());
                }
                this.CloseConnection();
                return list;
            }
            else
            {
                return list;
            }
        }
    }

Код в Form1

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            LoadData();
        }
        private void LoadData()
        {
            DBconnect db = new DBconnect();
            foreach (var s in db.Select())
            {
                dataGridView1.Rows.Add(s);
            }
        }
    }

Вот что получается в результате, прикрепляю скрин

Answer 1

Рассмотрим подробнее ваш пример. Вот вы "набросали" на форму контролы, и вам нужно начать программировать работу с ними. Что бы тут хотелось бы...

Во-первых, не торопитесь сразу создавать БД и подключаться к ней. Для быстрого прототипирования приложения БД не нужна и даже вредна, т.к. отвлекает время и внимание на работу с ней.

Во-вторых, в прил. необходимо выделить слои, минимально 3: слой отображения (визуальный интерфейс), слой модели предметной области с кот. работает ваше прил. и слой хранения (это как раз работа с БД).

Начнем с создания модели. У нас модель достаточно простая. Я добавил еще статич. метод для клонирования экземпляра класса, зачем? Объясню ниже.

public class Employee
{
    public int Id { get; set; }
    //порядковый номер для отображения в DGV
    public int OrderNumber { get; set; }
    //имя
    public string FirstName { get; set; }
    //фамилия
    public string LastName { get; set; }
    public string Phone { get; set; }
    public Employee(int id, string firstName = "<?>", string lastName = "<?>", string phone = "<?>")
    {
        Id = id;
        FirstName = firstName;
        LastName = lastName;
        Phone = phone;
    }
    /// <summary>
    /// Получение клонированного экземпляра
    /// </summary>
    /// <param name="employee">существующий экземпляр</param>
    /// <returns>клон существующего сотрудника</returns>
    public static Employee GetClone(Employee employee)
    {
        if (employee is null)
            throw new System.ArgumentNullException(nameof(employee));
        return new Employee(employee.Id)
        {
            FirstName = employee.FirstName,
            LastName = employee.LastName,
            Phone = employee.Phone,
        };
    }
    public override string ToString()
    {
        return $"{Id}: {FirstName} {LastName}";
    }
}

Слой хранения начнем с абстракции, с создания интерфейса репозитория.

public interface IEmployeeRepository
{
    //получение всех
    Task<Result<List<Employee>>> GetEmployees();
    //добавление
    Task<Result<int>> AddEmployee(Employee employee);
    //удаление
    Task<Result<int>> RemoveEmployee(int id);
    //обновление
    Task<Result<int>> UpdateEmployee(Employee emp);
}

Здесь мы объявляем все нужные нам для работы методы. Кстати, вы можете начинать прямо с пустого интерфейса, и по мере надобности добавлять в него нужные члены. Обратите внимание, что предполагается работа в асинхронном режиме, и да, есть еще какой-то Result<T>!

Result<T> - это пример т.н. монады, спец. класса для возвращения результата в случае если в методе возникнет ошибка или результат может быть равным null. Подробнее см.видео. Вот его код

/// <summary>
/// Монада Result для возвращения результата вместо null
/// и для случаев когда возникает Exception, а результат из метода
/// нужно возвращать какой-то
/// </summary>
/// <typeparam name="T"></typeparam>
public class Result<T>
{
    public readonly T Value;
    public readonly string Error;
    //ctors
    public Result(T value)
    {
        Value = value;
        Error = String.Empty;
    }
    public Result(string error)
    {
        Error = error;
    }
    public bool HasValue => String.IsNullOrEmpty(Error);
    public static implicit operator bool(Result<T> result)
    {
        return result.HasValue;
    }
}

Теперь вернемся к интерфейсу приложения. Код формы такой

public partial class MainForm : Form
{
    //Источник данных для DGV
    private BindingSource _bsEmployees;
    //редактируемый сотрудник
    private BindingSource _bsCurrentEmployee;
    //работа с БД
    private IEmployeeRepository _repo;
    public MainForm()
    {
        InitializeComponent();
        StartPosition = FormStartPosition.CenterScreen;
        Text = "Пример работы с MySql";
        //установка привязок
        SetBindings();
        this.Load += MainForm_Load;
    }
    private void MainForm_Load(object sender, EventArgs e)
    {
        //тестовый репозиторий
        _repo = new TestRepository();
        //Загрузка данных
        LoadData();
        //кнопки
        _buttonAdd.Click += ButtonAdd_Click;
        _buttonRemove.Click += ButtonRemove_Click;
        _buttonSave.Click += ButtonSave_Click;
        _buttonNext.Click += ButtonNext_Click;
        _buttonPrev.Click += ButtonPrev_Click;
        //клик по строке в DGV
        _dataGridViewEmployees.MouseClick += (s, a) => SetCurrentEmployee();
    }
    private void SetBindings()
    {
        _bsEmployees = new BindingSource();
        _bsEmployees.DataSource = typeof(List<Employee>);
        //привязки для DGV
        _dataGridViewEmployees.AutoGenerateColumns = false;
        _dataGridViewEmployees.DataSource = _bsEmployees;
        //привязки у столбцов
        _columnNumber.DataPropertyName = nameof(Employee.OrderNumber);
        _columnFirstName.DataPropertyName = nameof(Employee.FirstName);
        _columnLastName.DataPropertyName = nameof(Employee.LastName);
        _columnPhone.DataPropertyName = nameof(Employee.Phone);
        //текстбоксы
        _bsCurrentEmployee = new BindingSource();
        _bsCurrentEmployee.DataSource = new List<Employee> { new Employee(0) };
        _textBoxFirstName.DataBindings.Add("Text", _bsCurrentEmployee, nameof(Employee.FirstName));
        _textBoxLastName.DataBindings.Add("Text", _bsCurrentEmployee, nameof(Employee.LastName));
        _textBoxPhone.DataBindings.Add("Text", _bsCurrentEmployee, nameof(Employee.Phone));
    }
    private async void LoadData()
    {
        //получаем
        var result = await _repo.GetEmployees();
        if (result)
        {
            //извлекаем
            List<Employee> employees = result.Value;
            //пронумеровываем
            int i = 1;
            employees.ForEach(e => e.OrderNumber = i++);
            //отображаем
            _bsEmployees.DataSource = employees;
            _bsEmployees.MoveFirst();
            SetCurrentEmployee();
        }
        else
        {
            MessageBox.Show(result.Error, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
    private void ButtonAdd_Click(object sender, EventArgs e)
    {
        //курсор на последнего
        _bsEmployees.MoveLast();
        //след.порядковый номер
        int number = (_bsEmployees.Current as Employee).OrderNumber + 1;
        //добавляем нового
        _bsEmployees.Add(new Employee(0) { OrderNumber = number });
        //выделяем его
        _bsEmployees.MoveNext();
        SetCurrentEmployee();
        //выделяем имя для редактирования
        _textBoxFirstName.Focus();
    }
    private async void ButtonSave_Click(object sender, EventArgs e)
    {
        SwitchOnWaiting();
        var current = (Employee)_bsCurrentEmployee.Current;
        Result<int> result;
        try
        {
            if (current.Id == 0)
            {
                //добавляем нового сотрудника
                result = await _repo.AddEmployee(current);
            }
            else
            {
                //иначе обновляем существующего сотрудника
                result = await _repo.UpdateEmployee(current);
            }
            if (result)
            {
                //перечитываем данные
                LoadData();
            }
        }
        finally
        {
            SwitchOffWaiting();
        }
        if(!result)
        {
            MessageBox.Show(result.Error, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
    private async void ButtonRemove_Click(object sender, EventArgs e)
    {
        SwitchOnWaiting();
        //получаем текущего
        var employee = (Employee)_bsEmployees.Current;
        Result<int> result;
        try
        {
            //удаляем из БД
            result = await _repo.RemoveEmployee(employee.Id);
            if (result)
            {
                //удаляем из отображения
                _bsEmployees.Remove(employee);
                _bsEmployees.MoveFirst();
                SetCurrentEmployee();
            }
        }
        finally
        {
            SwitchOffWaiting();
        }
        if (!result)
        {
            MessageBox.Show(result.Error, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
    private void ButtonPrev_Click(object sender, EventArgs e)
    {
        _bsEmployees.MovePrevious();
        SetCurrentEmployee();
    }
    private void ButtonNext_Click(object sender, EventArgs e)
    {
        _bsEmployees.MoveNext();
        SetCurrentEmployee();
    }
    private void SetCurrentEmployee()
    {
        if (_bsEmployees.Count > 0)
        {
            _bsCurrentEmployee.List[0] = Employee.GetClone((Employee)_bsEmployees.Current);
        }
        else
        {
            _bsCurrentEmployee.List[0] = new Employee(0);
        }
        _bsCurrentEmployee.ResetItem(0);
    }
    private void SwitchOnWaiting()
    {
        foreach (var button in this.Controls.OfType<Button>())
        {
            button.Enabled = false;
        }
        _dataGridViewEmployees.Enabled = false;
        Cursor = Cursors.WaitCursor;
    }
    private void SwitchOffWaiting()
    {
        foreach (var button in this.Controls.OfType<Button>())
        {
            button.Enabled = true;
        }
        _dataGridViewEmployees.Enabled = true;
        Cursor = Cursors.Default;
    }
}

На что хотелось бы обратить внимание.

Работаем через привязки, используем для этого два экземпляра BindingSource, один для DataGridView, второй для текстбоксов текущего редактируемого или создаваемого нового сотрудника. По клику на DGV или переходе с пом.кнопок к следующему или предыдущему создается клон и привязывается текстбоксам. Сделано так для того, чтобы исключить одновременное изменение свойств выделенного сотрудника в DGV и пользователь понимал, что необходимо нажать кнопку Сохранить для запоминания изменений.

В методе MainForm_Load() сделано подключение к фейковой БД _repo = new TestRepository(); или точнее классу реализующему IEmployeeRepository c тестовыми данными. Рассмотрим его

class TestRepository : IEmployeeRepository
{
    private List<Employee> _employees;
    public TestRepository()
    {
        _employees = new List<Employee>
        {
            new Employee(1, "Иван", "Голунов", "+7561234567"),
            new Employee(2, "Сергей", "Смирнов", "+77861234567"),
            new Employee(3, "Дарья", "Смирнова", "+798475563"),
            new Employee(4, "Кристина", "Семяжко", "+7304985023"),
            new Employee(5, "Владимир", "Драгунов", "+73431234567"),
        };
    }
    public Task<Result<List<Employee>>> GetEmployees()
    {
        var result = new List<Employee>();
        foreach (var e in _employees)
        {
            var emp = new Employee(e.Id, e.FirstName, e.LastName, e.Phone);
            result.Add(emp);
        }
        return Task.FromResult(new Result<List<Employee>>(result));
    }
    public Task<Result<int>> AddEmployee(Employee employee)
    {
        if (employee is null)
            throw new ArgumentNullException(nameof(employee));
        if (String.IsNullOrWhiteSpace(employee.FirstName)
            || String.IsNullOrEmpty(employee.FirstName))
        {
            return Task.FromResult(new Result<int>("Введите имя сотрудника."));
        }
        if (String.IsNullOrWhiteSpace(employee.LastName)
            || String.IsNullOrEmpty(employee.LastName))
        {
            return Task.FromResult(new Result<int>("Введите фамилию сотрудника."));
        }
        if (employee is null || employee.Id > 0)
            throw new ArgumentNullException(nameof(employee));
        if (_employees.Count > 0)
        {
            employee.Id = _employees.Max(e => e.Id) + 1;
        }
        else
        {
            employee.Id = 1;
        }
        _employees.Add(employee);
        return Task.FromResult(new Result<int>(1));
    }
    public Task<Result<int>> RemoveEmployee(int id)
    {
        if (id <= 0)
            throw new ArgumentException(nameof(id));
        var emp = _employees.FirstOrDefault(e => e.Id == id);
        if (emp != null)
        {
            _employees.Remove(emp);
        }
        return Task.FromResult(new Result<int>(1));
    }
    public Task<Result<int>> UpdateEmployee(Employee employee)
    {
        if (employee is null)
            throw new ArgumentNullException(nameof(employee));
        if (String.IsNullOrWhiteSpace(employee.FirstName)
            || String.IsNullOrEmpty(employee.FirstName))
        {
            return Task.FromResult(new Result<int>("Введите имя сотрудника."));
        }
        if (String.IsNullOrWhiteSpace(employee.LastName)
            || String.IsNullOrEmpty(employee.LastName))
        {
            return Task.FromResult(new Result<int>("Введите фамилию сотрудника."));
        }
        var emp = _employees.FirstOrDefault(e => e.Id == employee.Id);
        if (emp != null)
        {
            emp.FirstName = employee.FirstName;
            emp.LastName = employee.LastName;
            emp.Phone = employee.Phone;
        }
        return Task.FromResult(new Result<int>(1));
    }
}

Представьте на минутку, вы фрилансер и у вас заказ на подобную программу. Вам нужно быстро разработать прототип и предоставить заказчику, чтоб он мог этот прототип запустить и посмотреть, оценить и проч. Если бы вы использовали сразу подключение к реальной БД у вас бы возникли трудности, не правда ли... А так без проблем, компилируем и отправляем экзешник по почте.

Заказчик доволен? :) Пишем работу с реальной БД.

class MySqlRepository : IEmployeeRepository
{
    public MySqlRepository()
    { }
    private MySqlConnection GetConnection()
    {
        var cs = ConfigurationManager.ConnectionStrings["MySqlConn"].ToString();
        var builder = new MySqlConnectionStringBuilder(cs);
        //чтоб избежать проблем с русским языком
        builder.CharacterSet = "utf8";
        return new MySqlConnection(builder.ConnectionString);
    }
    public async Task<Result<List<Employee>>> GetEmployees()
    {
        var list = new List<Employee>();
        try
        {
            using (var con = GetConnection())
            using (var cmd = con.CreateCommand())
            {
                cmd.CommandText = "SELECT * FROM employees";
                con.Open();
                using (var reader = await cmd.ExecuteReaderAsync())
                {
                    while (await reader.ReadAsync())
                    {
                        var emp = new Employee(reader.GetInt32(0));
                        emp.FirstName = reader.GetString(1);
                        emp.LastName = reader.GetString(2);
                        emp.Phone = reader.GetString(3);
                        list.Add(emp);
                    }
                }
            }
        }
        catch (MySqlException ex)
        {
            return new Result<List<Employee>>(GetUserFriendlyErrorMessage(ex));
        }
        catch (Exception ex)
        {
            return new Result<List<Employee>>(ex.Message);
        }
        return new Result<List<Employee>>(list);
    }
    public async Task<Result<int>> AddEmployee(Employee employee)
    {
        if (employee is null)
            throw new ArgumentNullException(nameof(employee));
        if (String.IsNullOrWhiteSpace(employee.FirstName)
            || String.IsNullOrEmpty(employee.FirstName))
        {
            return new Result<int>("Введите имя сотрудника.");
        }
        if (String.IsNullOrWhiteSpace(employee.LastName)
            || String.IsNullOrEmpty(employee.LastName))
        {
            return new Result<int>("Введите фамилию сотрудника.");
        }
        int result = 0;
        try
        {
            using (var con = GetConnection())
            using (var cmd = con.CreateCommand())
            {
                cmd.CommandText = "INSERT INTO employees (first_name, last_name, phone)" +
                    " VALUES(@firstName, @lastName, @phone)";
                cmd.Parameters.Add(new MySqlParameter("@firstName", MySqlDbType.VarChar, 200)
                { Value = employee.FirstName });
                cmd.Parameters.Add(new MySqlParameter("@lastName", MySqlDbType.VarChar, 300)
                { Value = employee.LastName });
                cmd.Parameters.Add(new MySqlParameter("@phone", MySqlDbType.VarChar, 45)
                {
                    Value = employee.Phone ?? (object)System.DBNull.Value
                });
                con.Open();
                result = await cmd.ExecuteNonQueryAsync();
            }
        }
        catch (MySqlException ex)
        {
            return new Result<int>(GetUserFriendlyErrorMessage(ex));
        }
        catch (Exception ex)
        {
            return new Result<int>(ex.Message);
        }
        return new Result<int>(result);
    }
    public async Task<Result<int>> RemoveEmployee(int id)
    {
        if (id <= 0)
            throw new ArgumentException(nameof(id));
        int result = 0;
        try
        {
            using (var con = GetConnection())
            using (var cmd = con.CreateCommand())
            {
                cmd.CommandText = "DELETE FROM employees WHERE id =@id";
                cmd.Parameters.Add(new MySqlParameter("@id", MySqlDbType.Int32)
                { Value = id });
                con.Open();
                result = await cmd.ExecuteNonQueryAsync();
            }
        }
        catch (MySqlException ex)
        {
            return new Result<int>(GetUserFriendlyErrorMessage(ex));
        }
        catch (Exception ex)
        {
            return new Result<int>(ex.Message);
        }
        return new Result<int>(result);
    }
    public async Task<Result<int>> UpdateEmployee(Employee employee)
    {
        if (employee is null)
            throw new ArgumentNullException(nameof(employee));
        if (String.IsNullOrWhiteSpace(employee.FirstName)
            || String.IsNullOrEmpty(employee.FirstName))
        {
            return new Result<int>("Введите имя сотрудника.");
        }
        if (String.IsNullOrWhiteSpace(employee.LastName)
            || String.IsNullOrEmpty(employee.LastName))
        {
            return new Result<int>("Введите фамилию сотрудника.");
        }
        int result = 0;
        try
        {
            using (var con = GetConnection())
            using (var cmd = con.CreateCommand())
            {
                cmd.CommandText = "UPDATE employees" +
                    " SET first_name = @firstName, last_name = @lastName, phone = @phone" +
                    " WHERE id =@id";
                cmd.Parameters.Add(new MySqlParameter("@firstName", MySqlDbType.VarChar, 200)
                { Value = employee.FirstName });
                cmd.Parameters.Add(new MySqlParameter("@lastName", MySqlDbType.VarChar, 300)
                { Value = employee.LastName });
                cmd.Parameters.Add(new MySqlParameter("@phone", MySqlDbType.VarChar, 45)
                {
                    Value = employee.Phone ?? (object)System.DBNull.Value
                });
                cmd.Parameters.Add(new MySqlParameter("@id", MySqlDbType.Int32)
                { Value = employee.Id });
                con.Open();
                result = await cmd.ExecuteNonQueryAsync();
            }
        }
        catch (MySqlException ex)
        {
            return new Result<int>(GetUserFriendlyErrorMessage(ex));
        }
        catch (Exception ex)
        {
            return new Result<int>(ex.Message);
        }
        return new Result<int>(result);
    }
    private string GetUserFriendlyErrorMessage(MySqlException ex)
    {
        var message = String.Empty;
        switch (ex.Number)
        {
            case 0:
                if (ex.InnerException.Message.Contains("Unknown"))
                {
                    message = "Неверное название схемы или таблицы.";
                }
                else if (ex.InnerException.Message.Contains("Access"))
                {
                    message = "Неверное имя или пароль доступа.";
                }
                else
                {
                    message = ex.Message;
                }
                break;
            case 1042:
                message = "Сервер по указанному адресу не доступен." +
                    "\nОшибка ожидания.";
                break;
            case 1045:
                message = "Неверное имя пользователя или пароль, " +
                    "\nпожалуйста, попробуйте еще раз.";
                break;
            default:
                message = ex.Message;
                break;
        }
        return message;
    }
}

В методе GetConnection() параметры соединения читаются из файла App.config

<?xml version="1.0" encoding="utf-8" ?>
   <configuration>
       <startup> 
           <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
       </startup>
       <connectionStrings>
           <add name="MySqlConn"
            providerName="MySql.Data.MySqlClient"
     connectionString="Server=192.168.0.250;Port=3306;Database=EmployeesDb;Uid=admin;
      Pwd=Mysql17;"/>
      </connectionStrings>
 </configuration>

Для работы с этим классом, нужно вернуться в код формы и в методе MainForm_Load() изменить строчку получения экземпляра репозитория _repo = new MySqlRepository();.

Да, и не забудьте сначала получить деньги от заказчика :)

Пример лежит здесь.

Answer 2

Для конструирования строки соединения можно использовать специальный класс-билдер.

При установлении соединения вы оставили только два случая в switch/case, а остальные отбрасываются. В итоге пользователь не получит никакого сообщения, если что-то пойдёт не так. Нужно, например, добавить дополнительную ветку default.

Современная разработка подразумевает использования моделей данных. Свойства класса-модели должны соответствовать колонкам в таблице базы данных. Я не знаю, какие у вас колонки, но, судя по форме, это Имя, Фамилия, Телефон. Поэтому, класс-модель будет такой:

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Phone { get; set; }
}

Добавьте необходимые свойства с нужными типами (например, Id типа int и т. п.)

При чтении данных из БД создаём экземпляры нашего класса-модели, заполняем его свойства и добавляем в список.

class DBconnect
{
    private readonly MySqlConnection connection;
    public DBconnect()
    {
        var builder = new MySqlConnectionStringBuilder();
        builder.Server = "localhost";
        builder.Database = "catalog_personal";
        builder.UserID = "root";
        //builder.Password = "";
        connection = new MySqlConnection(builder.ConnectionString);
    }
    private bool OpenConnection()
    {
        try
        {
            connection.Open();
            return true;
        }
        catch (MySqlException ex)
        {
            switch (ex.Number)
            {
                case 0:
                    MessageBox.Show("Невозможно подключиться к серверу, " +
                        "связаться с админ-панелью");
                    break;
                case 1045:
                    MessageBox.Show("Неверное имя пользователя / пароль, " +
                        "пожалуйста, попробуйте еще раз");
                    break;
                default:
                    MessageBox.Show(ex.Message);
                    break;
            }
            return false;
        }
    }
    private void CloseConnection()
    {
        try
        {
            connection.Close();
        }
        catch (MySqlException ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
    public List<Person> Select()
    {
        string query = " SELECT * FROM personal";
        var list = new List<Person>();
        if (OpenConnection())
        {
            using (var cmd = new MySqlCommand(query, connection))
            using (var dataReader = cmd.ExecuteReader())
            {
                while (dataReader.Read())
                {
                    var person = new Person();
                    person.FirstName = dataReader.GetString(0);
                    person.LastName = dataReader.GetString(1);
                    person.Phone = dataReader.GetString(2);
                    list.Add(person);
                }
            }
            CloseConnection();
        }
        return list;
    }
}

Также используем привязку данных (binding) вместо ручного добавления.

private void LoadData()
{
    var db = new DBconnect();
    dataGridView1.DataSource = db.Select();
}
Answer 3

Переписал ваш код через MySqlDataAdapter, он очень сильно сократился.

Как упражнение, можете переписать его через модели (будет чуть побольше и посложнее, но правильнее и гибчее).

class DBconnect
    {
        private MySqlConnection connection;
        private string server, database, uid, password;
        public DBconnect()
        {
            Initialize();
        }
        private void Initialize()
        {
            ...
        }
        //Открываем соединение
        private bool OpenConnection()
        {
            ...
        }
        //Закрываем соединение
        private bool CloseConnection()
        {
            ...
        }
        public DataTable Select()
        {
            var dt = new DataTable();
            if (this.OpenConnection() == true)
            {
                MySqlDataAdapter da = new MySqlDataAdapter();
                da.SelectCommand.Connection = this.connection;
                da.SelectCommand.CommandText = " SELECT * FROM personal";
                da.Fill(dt);
                this.CloseConnection();
            }
            return dt;
        }
    }

Код в Form1

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            LoadData();
        }
        private void LoadData()
        {
            DBconnect db = new DBconnect();
            dataGridView1.DataSource = db.Select();
        }
    }
READ ALSO
Сonversion failed when converting date and or/time from a character to string c# Помогите Решить [дубликат]

Сonversion failed when converting date and or/time from a character to string c# Помогите Решить [дубликат]

Никак не могу решить проблему с конверсиейВ БД значение столбцов : date и time, использую DateTimePicker в WinForms и создаю новые переменные в которые записываю...

112
Валидация кода на C#

Валидация кода на C#

Есть файлы расширения cs, которые генерируются утилитойМне необходимо программно проверять на корректность сгенерируемые файлы программно

124
Где Word хранит свои картинки?

Где Word хранит свои картинки?

В общем, есть много Word'ов, которые я обрабатываю через interop и пытаюсь вытянуть картинки, что бы их сохранить отдельно

85
Как связать List с ListView в XAML?

Как связать List с ListView в XAML?

Подскажите как в Xaml, через DataContext или ItemSource(или я не правильно думаю, что бы прибиндить из XAML свою коллекцию _ListProduct(Желательно с тремя столбиками,...

90