C# Cơ bản .NET Core §1) Cài đặt, chương trình C# đầu tiên §2) Biến, kiểu dữ liệu và nhập/xuất §3) Toán tử số học và gán §4) So sánh, logic và lệnh if, switch §5) Vòng lặp for, while §6) Phương thức - Method §7) Phương thức - Delegate §8) Lớp - Class §9) Kiểu vô danh và dynamic §10) Biểu thức lambda §11) Event §12) Hàm hủy - Quá tải toán tử - thành viên tĩnh - indexer §13) Lớp lồng nhau - namespace §14) null và nullable §15) Mảng §16) Chuỗi ký tự §17) Tính kế thừa §18) Tính đa hình - abstract - interface §19) Struct và Enum §20) Ngoại lệ Exeption §21) IDisposable - using §22) File cơ bản §23) FileStream §24) Generic §25) Collection - List §26) SortedList §27) Queue / Stack §28) Linkedlist §29) Dictionary - HashSet §30) Phương thức mở rộng §31) ObservableCollection §32) LINQ §33) (Multithreading) async - bất đồng bộ §34) Type §35) Attribute Annotation §36) DI Dependency Injection §37) (Multithreading) Parallel §38) (Networking) HttpClient §39) (Networking) HttpMessageHandler §40) (Networking) HttpListener §41) (Networking) Tcp TcpListenerr/TcpClient §42) (ADO.NET) SqlConnection §43) (ADO.NET) SqlCommand §44) (EF Core) Tổng quan §45) (EF Core) Tạo Model §46) (EF Core) Fluent API §47) (EF Core) Query §48) (EF Core) Scaffold §49) (EF Core) Migration §50) (ASP.NET CORE) Hello World! §51) (ASP.NET CORE) Middleware §52) (ASP.NET CORE) Map - Request - Response §53) (ASP.NET CORE) IServiceCollection - MapWhen §54) (ASP.NET CORE) Session - ISession §55) (ASP.NET CORE) Configuration §56) (ASP.NET CORE MVC) Controller - View
Lập trình C# (C Sharp)

Giới thiệu về ADO.NET

ADO.NET là tập hợp các thư viện lớp qua đó cho phép ứng dụng tương tác (lấy về, cập nhật, xóa) với các nguồn dữ liệu (Như SQLServer, XML, MySQL, Oracle Database ...).

Kiến trúc để truy cập dữ liệu với ADO.NET được phân ra nhiều phần rời rạc, mỗi phần có thể sử dụng độc lập hay đồng thời nhiều thành phần được sử dụng. Cơ bản thì nó phân chia ra hai khu vực như hình dưới:

Kiến trúc ADO.NET
  • Phần thứ nhất gọi là Data Provider: là các thư viện lớp cung cấp chức năng tạo kết nối đến nguồn dữ liệu, thi hành các lệnh trên nguồn dữ liệu đó inset, update, delete, read.

    SQL Server: Loại Data Provider mặc định trong .NET CoreSqlClient ở namespace System.Data.SqlClient cung cấp khả năng kết nối đến SQL Server
    MySQL: Nếu muốn có loại Data Provider truy cập đến MySQL thì cài đặt package MySql.Data, sẽ có Data Provider MySql.Data.MySqlClient

    SQLite thì cài đặt Data Provider Microsoft.Data.SQLite

  • Phần thứ 2 gọi là DataSet là các thư viện lớp (độc lập với Data Provider) tạo ra các đối tượng để quản lý dữ liệu không phụ thuộc ngồn dữ liệu đến từ đâu, đã ở trong ứng dụng (local) hay từ nguồn XML.
    DataSet thường gồm nhiều DataTable, trong DataTable lại gồm DataColumn, các dàng buộc, các khóa chính ... Vậy DataSet là sự trừu tượng hóa một CSDL thực.

Trước tiên tìm hiểu sử dụng Data Provider với trường hợp cụ thể là SqlClient để truy cập đến CSDL MS SQL Server. Hãy gõ lệnh sau để thêm package SqlClient vào dự án:

dotnet add package System.Data.SqlClient

Sau đó trong code sử dụng thêm namespace:

using System.Data;
using System.Data.SqlClient;

Chuẩn bị SQL Server với dữ liệu mẫu

Do thực hành sử dụng SqlClient kết nối SQL Server, nên nếu chưa có hệ quản trị CSDL này thì có thể tạo một SQL Server với dữ liệu mẫu - chạy trong một Container Docker, hãy làm theo hướng dẫn phần MSSQL Container, nếu đã có SQL Server - bạn có thể phục hồi dữ liệu mẫu từ file bak xtlab.bak vào CSDL xtlab để thực hành.

Tạo kết nối với SqlConnection

SqlConnection (System.Data.SqlClient.SqlConnection) là lớp biểu diễn sự kết nối tới SQL Server. Sử sử dụng SqlConnection thực hiện như sau:

  • Tạo đối tượng SqlConnection từ một chuỗi kết nối tới SQL Server
  • Mở kết nối với phương thức Open()
  • Thực hiện các truy vấn bằng cách sử dụng các lớp như SqlCommand, SqlDataAdapter, SqlDataReader ...
  • Không còn sử dụng đến kết nối nữa thì cần đóng lại bằng phương thức Close

Ví dụ, có SQL Server ở địa chỉ localhost (hoặc 127.0.0.1), cổng kết nổi 1433, tên tài khoản là SA, password là Password123, thì tạo và mở kết nối như sau:

string sqlconnectStr     = "Data Source=localhost,1433;Initial Catalog=xtlab;User ID=SA;Password=Password123";
SqlConnection connection = new SqlConnection(sqlconnectStr);

connection.Open();                      //  Mở kết nối - hoặc  connection.OpenAsync(); nếu dùng async
/.. thực hiện cá tác  vụ truy vấn CSDL
connection.Close();                     // Đóng kết nối

Tạo chuỗi kết nối với SQL Server

Chuỗi kết nối (connection string) là tham số để khởi tạo ra đối tượng SqlConnection, chuỗi này chứa các thông tin cơ bản để thực hiện kết nối đến một SQL Server, các thông tin được chứa theo cặp key=value; ví dụ chuỗi "key 1=value1;key 2=value2", dưới dây tham khảo một số key

KEY Mô tả
Connect Timeout Số giây cố gắng kết nối trước khi phát sinh lỗi (mặc định 15s)
Timeout
Connection Timeout
Data Source Key này dùng để gán địa chỉ mạng (tên máy hoặc IP hoặc domain) của SQL Server, hoặc là tên của hiện hành đang chạy của SQL Server. Nếu muốn gán cả cổng thì sẽ thêm vào phía sau địa chỉ này ,port
Server
Address
Addr
Initial Catalog Tên của Database
Database
Password Password để kết nối
PWD
User ID Tài khoản (account) dùng để đăng nhập
UID

Tạo chuỗi kết nối cơ bản

Chuỗi có dạng như sau:

Server=ServerAddress;Database=DataBaseName;User Id=Username;Password=myPassword;

Hoặc

Data Source=ServerAddress;Database=DataBaseName;User Id=Username;Password=myPassword;

Ví dụ

SQL Server ở máy có địa chỉ IP 192.168.1.10, có CSDL tên exampledb, cho phép kết nối với User/Password là testuser/testpass, thì tạo ra chuỗi kết nối và đối tượng SqlConnection như sau:

String connectionString = "Server=192.168.1.10;Database=exampledb;User Id=testuser;Password=testpass;";
SqlConnection sqlConnection = new SqlConnection(connectionString);
sqlConnection.Open();   //Mở kết nối
//...Code truy vấn, cập nhật dữ dữ liệu ở đây
sqlConnection.Close();  //Đóng kết nối sau khi sử dụng

Nếu sử dụng using thì kết nối sẽ tự động đóng lại ở cuối khối using, nên không cần phải gọi Close

String connectionString = "Server=192.168.1.10;Database=exampledb;User Id=testuser;Password=testpass;";
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
    sqlConnection.Open();//Mở kết nối
    //...Code truy vấn, cập nhật dữ dữ liệu ở đây
}

SqlConnectionStringBuilder

SqlConnectionStringBuilder giúp tạo ra chuỗi kết nối, bằng cách thiết lập từng loại key ở trên, sau đó nó phát sinh chuỗi kết nối giúp bạn. Ví dụ:

SqlConnectionStringBuilder stringBuilder = new SqlConnectionStringBuilder();
stringBuilder["Server"]     = "127.0.0.1,1433";
stringBuilder["Database"]   = "xtlab";
stringBuilder["User Id"]    = "SA";
stringBuilder["Password"]   = "Password123";

string sqlConnectStr        = stringBuilder.ToString();

using(SqlConnection connection = new SqlConnection(sqlConnectStr))
{
    connection.Open();
    // Thực hiện  các tác vụ
}

Thông tin kết nối SqlConnection

Ở phần trên đã biết tạo ra một chuỗi kết nối, từ đó sinh ra đối tượng SqlConnection, đối tượng này được sử dụng bởi các lớp khác nhau như SqlCommand, SqlDataAdapter ... để thực hiện các truy vấn đến dữ liệu. Những đối tượng này sẽ tìm hiều ở phần sau, ở đây nói thêm một chút về SqlConnection

Một số phương thức, thuộc tính SqlConnection

State Kiểu ConnectionState trạng thái kết nối:
  • ConnectionState.Closed kết nối đã đóng
  • ConnectionState.Connecting đang kết nối
  • ConnectionState.Executing đang thi hành lệnh nào đó
  • ConnectionState.Fetching đang nhận dữ liệu về
  • ConnectionState.Open kết nối đang mở

Để kiểm tra cần thực hiện phép toán bitwise bằng phương thức FlagsAttribute, ví dụ:

if ((connection.State.HasFlag(ConnectionState.Open))
    && (connection.State.HasFlag(ConnectionState.Fetching)))
    {
        Console.WriteLine("Kết nối mở và đang nhận dữ liệu");
    }
Database Trả về tên Database - sau khi kết nối mở
StatisticsEnabled Mặc định là false, nếu thiết lập bằng true thì nó cho phép thu thập thông tin về kết nối. Để lấy thông tin thù thập được dùng phương thức RetrieveStatistics()
Open() Mở kết nối, sử dụng OpenAsync() nếu dùng kỹ thuật async
Close() Đóng kết nối
CreateCommand() Tạo đối tượng SqlCommand để thực hiện các lệnh SQL
RetrieveStatistics() Lấy thông tin thống kê (trả về IDictionary)
StateChange Event - phát sinh khi thay đổi trạng thái kết nối, muốn bắt sự kiện gán nó bằng delegate dạng
(object sender, StateChangeEventArgs e) => { /.. }

Ví dụ:

SqlConnectionStringBuilder stringBuilder = new SqlConnectionStringBuilder();
stringBuilder["Server"]     = "127.0.0.1,1433";
stringBuilder["Database"]   = "xtlab";
stringBuilder["User Id"]    = "SA";
stringBuilder["Password"]   = "Password123";

SqlConnection connection      = new SqlConnection(stringBuilder.ToString());
connection.StatisticsEnabled  = true;  // kích hoạt chế độ thu thập thống kê

// Bắt sự kiện trạng thái kết nối thay đổi
connection.StateChange += (object  sender, StateChangeEventArgs e) => {
        Console.WriteLine($"Trạng thái hiện tại: {e.CurrentState}, trạng thái trước: " + $"{e.OriginalState}");
};

connection.Open();  // mở kết nối

// Dùng SqlCommand thi hành SQL  - sẽ  tìm hiểu sau
using (SqlCommand command = connection.CreateCommand()) {
    command.CommandText = "select top(5) * from Products";
    var reader = command.ExecuteReader();
    Console.WriteLine("CÁC SẢN PHẨM:");
    Console.WriteLine($"{"ProductID", 10} {"ProductName"}");
    while (reader.Read()) {
        Console.WriteLine($"{reader["ProductID"], 10} {reader["ProductName"]}");
    }
}

Console.WriteLine($"{"ConnectionString", 17} : {stringBuilder}");
Console.WriteLine($"{"DataSource", 17} : {connection.DataSource}");


// Lấy thống kê và in số liệu thống kê
var dicStatics = connection.RetrieveStatistics();
foreach (var key in dicStatics.Keys)
{
    Console.WriteLine($"{key, 17} : {dicStatics[key]}");
}

connection.Close();

Đọc thông tin kết nối từ file config

Nếu muốn lưu chuỗi kết nối ở file config, bạn có thể sử dụng kỹ thuật Configuration đọc file json, hãy thêm các package như hướng dẫn tại config với json

dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Options.ConfigurationExtensions
dotnet add package Microsoft.Extensions.Configuration.Json

Giả sử tạo file config có tên là appconfig.json có lưu chuỗi kết nối như sau:

{
    "csdl" :  {
        "ketnoi1"  : "Data Source=127.0.0.1,1433;Initial Catalog=xtlab;User ID=SA;Password=Password123",
        "ketnoi2"  : "Data Source=localhost,1433;Initial Catalog=xtlab;User ID=SA;Password=Password123"
    }
}

Ví dụ:

using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using System.IO;

namespace ADO01
{
    class Program
    {
        public static string GetConnectString() {
            var configBuilder = new ConfigurationBuilder()
                       .SetBasePath(Directory.GetCurrentDirectory())      // file config ở thư mục hiện tại
                       .AddJsonFile("appconfig.json");                    // nạp config định dạng JSON
            var configurationroot = configBuilder.Build();                // Tạo configurationroot
            return configurationroot["csdl:ketnoi2"];

        }
        static void Main(string[] args)
        {

            SqlConnection connection = new SqlConnection(GetConnectString());
            connection.StatisticsEnabled = true;
            connection.FireInfoMessageEventOnUserErrors = true;

            connection.StateChange += (object  sender, StateChangeEventArgs e) => {
                    Console.WriteLine($"Trạng thái hiện tại: {e.CurrentState}, trạng thái trước: " + $"{e.OriginalState}");
            };

            connection.Open();

            // Dùng SqlCommand thi hành SQL  - sẽ  tìm hiểu sau
            using (SqlCommand command = connection.CreateCommand()) {
                command.CommandText = "select top(5) * from Products";
                var reader = command.ExecuteReader();
                Console.WriteLine("CÁC SẢN PHẨM:");
                Console.WriteLine($"{"ProductID", 10} {"ProductName"}");
                while (reader.Read()) {
                    Console.WriteLine($"{reader["ProductID"], 10} {reader["ProductName"]}");
                }
            }

            Console.WriteLine($"{"ConnectionString", 17} : {GetConnectString()}");
            Console.WriteLine($"{"DataSource", 17} : {connection.DataSource}");



            var dicStatics = connection.RetrieveStatistics();


            foreach (var key in dicStatics.Keys)
            {
                Console.WriteLine($"{key, 17} : {dicStatics[key]}");
            }

            connection.Close();

        }
    }
}
Source Code
Đăng ký theo dõi ủng hộ kênh