diff --git a/.gitignore b/.gitignore
index daa0e6d..5827186 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,3 +62,23 @@ coverage
*.sw?
*.tsbuildinfo
+
+logs/
+[b|B]in
+[o|O]bj
+.vs
+[E|e]xclude
+
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/contentModel.xml
+/.idea.SQLTutorial.iml
+/modules.xml
+/projectSettingsUpdater.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/CSharp/SQLTutorial/ADO-1-Start/ADO-1-Start.csproj b/CSharp/SQLTutorial/ADO-1-Start/ADO-1-Start.csproj
new file mode 100644
index 0000000..7611e3e
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-1-Start/ADO-1-Start.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net8.0
+ ADO_1_Start
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/CSharp/SQLTutorial/ADO-1-Start/Program.cs b/CSharp/SQLTutorial/ADO-1-Start/Program.cs
new file mode 100644
index 0000000..cf65c97
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-1-Start/Program.cs
@@ -0,0 +1,36 @@
+using MySqlConnector;
+
+namespace ADO_1_Start;
+
+public class Program
+{
+ private static readonly string Host = "rm-bp12z6hlv46vi6g8mro.mysql.rds.aliyuncs.com";
+ private static readonly string Database = "bunny_test";
+ private static readonly uint Port = 3306;
+ private static readonly string Username = "root";
+ private static readonly string Password = "0212zkw!";
+
+ public static void Main(string[] args)
+ {
+ var mySqlConnectionStringBuilder = new MySqlConnectionStringBuilder
+ {
+ Server = Host, Port = Port,
+ Database = Database,
+ UserID = Username, Password = Password
+ };
+ Console.WriteLine(mySqlConnectionStringBuilder.ConnectionString);
+ using (var mySqlConnection = new MySqlConnection(mySqlConnectionStringBuilder.ConnectionString))
+ {
+ mySqlConnection.Open();
+
+ var mySqlCommand = new MySqlCommand("select * from sys_user");
+ mySqlCommand.Connection = mySqlConnection;
+
+ var mySqlDataReader = mySqlCommand.ExecuteReader();
+ mySqlDataReader.Read();
+
+ for (var i = 0; i < mySqlDataReader.FieldCount; i++)
+ Console.Write(mySqlDataReader.GetName(i) + (i < mySqlDataReader.FieldCount - 1 ? "\t" : "\n"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/CSharp/SQLTutorial/ADO-Web-1-Connect/ADO-Web-1-Connect.csproj b/CSharp/SQLTutorial/ADO-Web-1-Connect/ADO-Web-1-Connect.csproj
new file mode 100644
index 0000000..579a0c7
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-1-Connect/ADO-Web-1-Connect.csproj
@@ -0,0 +1,16 @@
+
+
+
+ net8.0
+ enable
+ enable
+ WebApplication1
+
+
+
+
+
+
+
+
+
diff --git a/CSharp/SQLTutorial/ADO-Web-1-Connect/ADO-Web-1-Connect.csproj.user b/CSharp/SQLTutorial/ADO-Web-1-Connect/ADO-Web-1-Connect.csproj.user
new file mode 100644
index 0000000..9ff5820
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-1-Connect/ADO-Web-1-Connect.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ https
+
+
\ No newline at end of file
diff --git a/CSharp/SQLTutorial/ADO-Web-1-Connect/Controller/HomeController.cs b/CSharp/SQLTutorial/ADO-Web-1-Connect/Controller/HomeController.cs
new file mode 100644
index 0000000..f1203d8
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-1-Connect/Controller/HomeController.cs
@@ -0,0 +1,15 @@
+using Microsoft.AspNetCore.Mvc;
+using WebApplication1.Data;
+
+namespace WebApplication1.Controller;
+
+[Route("api/[controller]")]
+public class HomeController
+{
+ [HttpGet]
+ public string? Index()
+ {
+ var configuration = AppCConfigurationServices.Configuration;
+ return configuration.GetConnectionString("BunnyTest");
+ }
+}
\ No newline at end of file
diff --git a/CSharp/SQLTutorial/ADO-Web-1-Connect/Data/AppCConfigurationServices.cs b/CSharp/SQLTutorial/ADO-Web-1-Connect/Data/AppCConfigurationServices.cs
new file mode 100644
index 0000000..4b0616e
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-1-Connect/Data/AppCConfigurationServices.cs
@@ -0,0 +1,18 @@
+using Microsoft.Extensions.Configuration.Json;
+
+namespace WebApplication1.Data;
+
+public class AppCConfigurationServices
+{
+ static AppCConfigurationServices()
+ {
+ Configuration = new ConfigurationBuilder()
+ .Add(new JsonConfigurationSource
+ {
+ Path = "appsettings.json",
+ ReloadOnChange = true
+ }).Build();
+ }
+
+ public static IConfiguration Configuration { get; set; }
+}
\ No newline at end of file
diff --git a/CSharp/SQLTutorial/ADO-Web-1-Connect/Program.cs b/CSharp/SQLTutorial/ADO-Web-1-Connect/Program.cs
new file mode 100644
index 0000000..8c66695
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-1-Connect/Program.cs
@@ -0,0 +1,27 @@
+var builder = WebApplication.CreateBuilder(args);
+builder.Services.AddCors(options =>
+{
+ options.AddDefaultPolicy(policyBuilder => policyBuilder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
+});
+
+// Add services to the container.
+// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+builder.Services.AddEndpointsApiExplorer();
+builder.Services.AddSwaggerGen();
+builder.Services.AddControllers();
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+ app.UseSwagger();
+ app.UseSwaggerUI();
+}
+
+app.UseHttpsRedirection();
+app.UseCors();
+app.UseAuthorization();
+app.MapControllers();
+
+app.Run();
\ No newline at end of file
diff --git a/CSharp/SQLTutorial/ADO-Web-1-Connect/Properties/launchSettings.json b/CSharp/SQLTutorial/ADO-Web-1-Connect/Properties/launchSettings.json
new file mode 100644
index 0000000..8983b74
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-1-Connect/Properties/launchSettings.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:13883",
+ "sslPort": 44388
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "http://localhost:5153",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "applicationUrl": "https://localhost:7156;http://localhost:5153",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/CSharp/SQLTutorial/ADO-Web-1-Connect/WebApplication1.http b/CSharp/SQLTutorial/ADO-Web-1-Connect/WebApplication1.http
new file mode 100644
index 0000000..9e31f7a
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-1-Connect/WebApplication1.http
@@ -0,0 +1,6 @@
+@WebApplication1_HostAddress = http://localhost:5153
+
+GET {{WebApplication1_HostAddress}}/weatherforecast/
+Accept: application/json
+
+###
diff --git a/CSharp/SQLTutorial/ADO-Web-1-Connect/appsettings.Development.json b/CSharp/SQLTutorial/ADO-Web-1-Connect/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-1-Connect/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/CSharp/SQLTutorial/ADO-Web-1-Connect/appsettings.json b/CSharp/SQLTutorial/ADO-Web-1-Connect/appsettings.json
new file mode 100644
index 0000000..c3dd6b9
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-1-Connect/appsettings.json
@@ -0,0 +1,12 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*",
+ "ConnectionStrings": {
+ "BunnyTest": "Server=rm-bp12z6hlv46vi6g8mro.mysql.rds.aliyuncs.com;Port=3306;User ID=root;Password=0212zkw!;Database=bunny_test"
+ }
+}
diff --git a/CSharp/SQLTutorial/ADO-Web-2-Connect/ADO-Web-2-Connect.csproj b/CSharp/SQLTutorial/ADO-Web-2-Connect/ADO-Web-2-Connect.csproj
new file mode 100644
index 0000000..1bf4aaf
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-2-Connect/ADO-Web-2-Connect.csproj
@@ -0,0 +1,16 @@
+
+
+
+ net8.0
+ enable
+ enable
+ ADO_Web_2_Connect
+
+
+
+
+
+
+
+
+
diff --git a/CSharp/SQLTutorial/ADO-Web-2-Connect/ADO-Web-2-Connect.csproj.user b/CSharp/SQLTutorial/ADO-Web-2-Connect/ADO-Web-2-Connect.csproj.user
new file mode 100644
index 0000000..9ff5820
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-2-Connect/ADO-Web-2-Connect.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ https
+
+
\ No newline at end of file
diff --git a/CSharp/SQLTutorial/ADO-Web-2-Connect/Controller/HomeController.cs b/CSharp/SQLTutorial/ADO-Web-2-Connect/Controller/HomeController.cs
new file mode 100644
index 0000000..905815a
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-2-Connect/Controller/HomeController.cs
@@ -0,0 +1,76 @@
+using ADO_Web_2_Connect.Data;
+using ADO_Web_2_Connect.Helper;
+using ADO_Web_2_Connect.Model;
+using Microsoft.AspNetCore.Mvc;
+
+namespace ADO_Web_2_Connect.Controller;
+
+[Route("/api/[controller]")]
+public class HomeController : ControllerBase
+{
+ [HttpGet("Index")]
+ public IActionResult Index()
+ {
+ var connectionString = AppConfigurationServices.Configuration.GetConnectionString("BunnyTest");
+ return new OkObjectResult(connectionString);
+ }
+
+ [HttpGet]
+ public async Task>> GetAll()
+ {
+ const string sql = "SELECT * FROM news_type";
+ var readerAsync = await MysqlHelper.ExecuteReaderAsync(sql);
+
+ var newTypes = new List();
+ if (!readerAsync.HasRows) return newTypes;
+
+ while (readerAsync.Read())
+ newTypes.Add(new NewType
+ {
+ Id = readerAsync.GetInt32(0), NewsTypeTitle = readerAsync.GetString(1),
+ IsEnabled = readerAsync.GetBoolean(2)
+ });
+
+ readerAsync.Close();
+ return newTypes;
+ }
+
+ [HttpGet("GetById/{id:int}")]
+ public async Task> GetById(int id)
+ {
+ var sql = $"SELECT * FROM news_type WHERE id={id}";
+ var mySqlDataReader = await MysqlHelper.ExecuteReaderAsync(sql);
+
+ // 是否存在数据
+ if (!mySqlDataReader.HasRows) return new NotFoundResult();
+
+ var newType = new NewType();
+ while (mySqlDataReader.Read())
+ newType = new NewType
+ {
+ Id = mySqlDataReader.GetInt32(0),
+ NewsTypeTitle = mySqlDataReader.GetString(1),
+ IsEnabled = mySqlDataReader.GetBoolean(2)
+ };
+
+ mySqlDataReader.Close();
+ return newType;
+ }
+
+ [HttpPost]
+ public async Task Insert(NewType? newType)
+ {
+ if (newType == null) return 0;
+
+ var sql =
+ $"INSERT INTO news_type ( `id`, `news_type_title`, `is_enable` ) VALUES ( {newType.Id}, '{newType.NewsTypeTitle}', {newType.IsEnabled} )";
+ return await MysqlHelper.ExecuteQueryAsync(sql);
+ }
+
+ [HttpDelete]
+ public async Task DeleteById(int id)
+ {
+ var sql = $"DELETE FROM news_type WHERE id={id}";
+ return await MysqlHelper.ExecuteQueryAsync(sql);
+ }
+}
\ No newline at end of file
diff --git a/CSharp/SQLTutorial/ADO-Web-2-Connect/Data/AppConfigurationServices.cs b/CSharp/SQLTutorial/ADO-Web-2-Connect/Data/AppConfigurationServices.cs
new file mode 100644
index 0000000..6e07175
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-2-Connect/Data/AppConfigurationServices.cs
@@ -0,0 +1,17 @@
+using Microsoft.Extensions.Configuration.Json;
+
+namespace ADO_Web_2_Connect.Data;
+
+public class AppConfigurationServices
+{
+ static AppConfigurationServices()
+ {
+ Configuration = new ConfigurationBuilder().Add(new JsonConfigurationSource
+ {
+ Path = "appsettings.json",
+ ReloadOnChange = true
+ }).Build();
+ }
+
+ public static IConfiguration Configuration { get; set; }
+}
\ No newline at end of file
diff --git a/CSharp/SQLTutorial/ADO-Web-2-Connect/Helper/MysqlHelper.cs b/CSharp/SQLTutorial/ADO-Web-2-Connect/Helper/MysqlHelper.cs
new file mode 100644
index 0000000..918fa2b
--- /dev/null
+++ b/CSharp/SQLTutorial/ADO-Web-2-Connect/Helper/MysqlHelper.cs
@@ -0,0 +1,108 @@
+using System.Data;
+using ADO_Web_2_Connect.Data;
+using MySqlConnector;
+
+namespace ADO_Web_2_Connect.Helper;
+
+public class MysqlHelper
+{
+ private static readonly string? ConnStr;
+
+ static MysqlHelper()
+ {
+ ConnStr ??= AppConfigurationServices.Configuration.GetConnectionString("BunnyTest");
+ }
+
+ ///
+ /// 查询数据库
+ ///
+ /// SQL语句
+ ///
+ public static int ExecuteNonQuery(string sql)
+ {
+ using var mySqlConnection = new MySqlConnection(ConnStr);
+ mySqlConnection.Open();
+ var command = new MySqlCommand(sql, mySqlConnection);
+ return command.ExecuteNonQuery();
+ }
+
+ ///
+ /// 异步查询数据库
+ ///
+ /// SQL语句
+ ///
+ public static async Task ExecuteQueryAsync(string sql)
+ {
+ await using var mySqlConnection = new MySqlConnection(ConnStr);
+ mySqlConnection.Open();
+ var command = new MySqlCommand(sql, mySqlConnection);
+ return await command.ExecuteNonQueryAsync();
+ }
+
+ ///
+ /// 读取数据库流
+ ///
+ /// SQL语句
+ ///
+ public static MySqlDataReader ExecuteReader(string sql)
+ {
+ using var mySqlConnection = new MySqlConnection(ConnStr);
+ mySqlConnection.Open();
+ var command = new MySqlCommand(sql, mySqlConnection);
+ return command.ExecuteReader(CommandBehavior.CloseConnection);
+ }
+
+ ///
+ /// 异步读取数据库流
+ ///
+ /// SQL语句
+ ///
+ public static async Task ExecuteReaderAsync(string sql)
+ {
+ var mySqlConnection = new MySqlConnection(ConnStr);
+ mySqlConnection.Open();
+ var command = new MySqlCommand(sql, mySqlConnection);
+ return await command.ExecuteReaderAsync();
+ }
+
+ ///
+ /// 异步读取数据库流
+ ///
+ /// SQL语句
+ ///
+ public static async Task ExecuteReaderAsyncTest(string sql)
+ {
+ await using var mySqlConnection = new MySqlConnection();
+ mySqlConnection.Open();
+ var command = new MySqlCommand(sql, mySqlConnection);
+ return await command.ExecuteReaderAsync(CommandBehavior.CloseConnection);
+ }
+
+ ///
+ /// 获取首行首列的值
+ ///
+ /// SQL语句
+ ///
+ public static object? ExecuteScalar(string sql)
+ {
+ using var mySqlConnection = new MySqlConnection(ConnStr);
+ mySqlConnection.Open();
+ var mySqlCommand = mySqlConnection.CreateCommand();
+ mySqlCommand.CommandText = sql;
+ mySqlCommand.CommandType = CommandType.Text;
+ return mySqlCommand.ExecuteScalar();
+ }
+
+ ///
+ /// 异步获取首行首列
+ ///
+ /// SQL语句
+ ///
+ public static async Task