Есть ли способ сделать эту форму C# DataGridView с MySQL, упростить настройку? В этом примере проекта я использую таблицу лиц базы данных myDB для заполнения DataGridView и обработки методов CRUD.
Этот простой проект обрабатывает людей в базе данных: вы можете добавлять новых людей в базу данных, удалять, обновлять или читать. Я сделал проект настолько компактным, насколько мог, но думаю, что он мог бы быть короче и проще для понимания.
В данном случае dt — это мое имя DataGridView, я создал функцию запроса, чтобы сделать ее более четкой и понятной, и обновляю базу данных mysql с помощью адаптера и функции обновления построителя команд.
Я перебираю таблицы DataSet и обновляю каждую таблицу. Имя запроса будет именем имени таблицы в DataSet.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MySqlConnector;
namespace WPF_crud
{
public partial class Form1 : Form
{
const string con = "server=localhost;database=myDB;username=root;";
MySqlConnection connection= new MySqlConnection(con);
//act as a bridge between a DataSet and a MySQL database for retrieving and saving data
MySqlDataAdapter adapter;
//DataSet is storing the data what he gets from the adapter (in correct variable string,int,bool stb.) it can store multiple tables from a query
DataSet data = new DataSet();
//automatically generates SQL commands (such as SELECT, INSERT, UPDATE, DELETE)
MySqlCommandBuilder command = new MySqlCommandBuilder();
public void Query(string query)
{
// Create a MySqlDataAdapter to fill a DataSet
adapter = new MySqlDataAdapter(query, connection);
command = new MySqlCommandBuilder(adapter);
data.Clear();
//fill the DataSet
adapter.Fill(data, "table");
//fill the DataGridView with the DataSet specified table
dt.DataSource = data.Tables["table"];
}
public Form1()
{
InitializeComponent();
//only for design not required
dt.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dt.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
Query("SELECT * FROM person where 1");
}
private void btn_Save_Click(object sender, EventArgs e)
{
adapter.Update(data, "table");
Query("SELECT * FROM person where 1");
}
private void btn1_Click(object sender, EventArgs e)
{
Query("SELECT * FROM person where age < 50");
}
private void btn2_Click(object sender, EventArgs e)
{
Query("SELECT * FROM person where age > 50");
}
private void btn3_Click(object sender, EventArgs e)
{
Query("SELECT * FROM person where name like '%a%'");
}
}
}





Из-за пула соединений повторное использование одного и того же объекта соединения является неправильным. Объекты соединения, которые вы видите в коде, уже являются тонкой/легкой оболочкой над гораздо более тяжелым объектом, управляемым через пул, и когда вы сохраняете тот же объект соединения, вы оптимизируете эту тонкую оболочку за счет гораздо «более тяжелого» реального соединения. Другими словами, вам следует только сохранить/поделиться строкой подключения, и вам действительно нужен совершенно новый объект подключения для большинства запросов.
Хуже того, метод Query(), показанный здесь, заставит вас написать безумно уязвимый для атак SQL-инъекций код... такого рода вещи, когда в следующем году вы узнаете, что вас взломали шесть месяцев назад, и вам посчастливилось сравнять счет. так далеко. Фактически, единственное, что вы могли бы сделать для безопасности хуже, — это сохранять пароли в виде обычного текста (вы же не сохраняете пароли в виде обычного текста, верно?)
Это настолько важно, что вы не должны даже упускать его из виду для практики, обучения или проверки концепции.
Вместо этого вам нужен механизм, {strike}позволяющий{/strike} принудительно передавать параметры в запросы отдельно от самой строки SQL (читайте о параметризованных запросах).
Но кроме того, после исправления метода Query() для использования параметров, я бы также изменил его, чтобы в результате он возвращал данные. Таким образом, отображение данных в сетке выглядит примерно так:
dt.DataSource = Query("SOME SQL", new string[} {"some parameter", "some other parameter"});
Как только мы зайдём так далеко, вы также обнаружите, что часто имеет смысл поместить этот материал в отдельный статический класс:
public static class DB
{
private static readonly string connectionString = "connection string here";
// you can still have a Query() method, but make it PRIVATE to the class
// and have it ask for an argument for query parameters.
private static DataTable Query(string sql, IEnumerable<(string, string)> parameters=null)
{
using var cn = new MySqlConnection(connectionString);
using var cmd = new MySqlCommand(sql, cn);
using var da = new MySqlDataAdapater(cmd);
if (parameters is object)
{
foreach(var parameter in parameters)
{
cmd.AddWithValue(parameter.Item1, parameter.Item2);
}
}
var result = new DataTable();
da.Fill(result);
return result;
}
// now have a PUBLIC method for each query:
public static DataTable MaxAge(int age)
{
string sql = "SELECT * FROM person where age < @MaxAge";
return Query(sql, new (string, string)[] {("@MaxAge", age.ToString())});
}
public static DataTable MinAge(int age)
{
string sql = "SELECT * FROM person where age > @MaxAge";
return Query(sql, new (string, string)[] {("@MaxAge", age.ToString())});
}
public static DataTable NameContains(string name)
{
// LIKE queries with a leading wildcard are SLOOOOW! Avoid when possible!
string sql = "SELECT * FROM person where name like '%' + @Name + '%'";
return Query(sql, new (string, string)[] {("@MaxAge", name)});
}
}
Теперь я знаю, что кажется, что я усложнил задачу, а не упростил ее, но посмотрите, как теперь будут выглядеть методы нажатия кнопок:
// Give these buttons meaningful names!
private void btn1_Click(object sender, EventArgs e)
{
dt.DataSource=DB.MaxAge(50);
}
private void btn2_Click(object sender, EventArgs e)
{
dt.DataSource=DB.MinAge(50);
}
private void btn3_Click(object sender, EventArgs e)
{
dt.DataSource = DB.NameContains("a");
}
Наконец я вижу это:
Я обновляю базу данных mysql с помощью адаптера и функции обновления построителя команд.
Кроме того, почти всегда лучше либо написать эти запросы INSERT/UPDATE/DELETE самостоятельно, либо получить настоящее решение ORM.