ConnectionString cho Entity Framework Core từ A-Z

Nếu bạn giống tôi, bạn sẽ thiết lập DbContext của Entity Framework Core và ConnectionString của bạn một lần trong class Startup và quên nó đi. Chuỗi kết nối (connection string) là những phần thiết yếu của một ứng dụng đang hoạt động, nhưng chúng ta thường quên mất các thành phần của chúng vì chúng ta không tương tác với chúng thường xuyên.

Chúng tôi sẽ hướng dẫn cách thiết lập các chuỗi kết nối cho SQL Server, Azure SQL, SQLite, PostgreSQL, MySQL và MariaDB trong bài viết này. Đây là những cơ sở dữ liệu phổ biến nhất được hỗ trợ bởi Entity Framework Core và có thể là thứ mà hầu hết các nhà phát triển đang hướng tới khi bắt đầu một ứng dụng mới.

SQL Server và Azure SQL

Có thể là cơ sở dữ liệu phổ biến nhất được sử dụng trong không gian .NET, các chuỗi kết nối SQL Server có thể từ đơn giản đến phức tạp đến kinh ngạc. Tôi đã cố gắng liệt kê những gì tôi nghĩ rằng các cấu hình phổ biến nhất sẽ dành cho hầu hết mọi người.

Điều quan trọng cần lưu ý là trình cung cấp dữ liệu SQL Server sử dụng System.Data.SqlClient để giao tiếp với phiên bản cơ sở dữ liệu. Ngoài ra, thư viện có các biện pháp phục hồi được tích hợp sẵn để xử lý các lỗi thoáng qua gần như được đảm bảo xảy ra trong môi trường đám mây.

Đối với người dùng Azure SQL, bạn có thể muốn sử dụng chuỗi kết nối được cung cấp trong môi trường do quản trị viên Azure của bạn tạo. Sau đó, bạn sẽ tìm hiểu cách cấu hình chuỗi kết nối cho bất kỳ trình cung cấp dữ liệu nào trong ASP.NET Core.

Kết nối chuẩn SQL Server

Chuỗi kết nối này dành cho những người sử dụng phiên bản SQL Server được cài đặt cục bộ. Thay đổi các giá trị cho địa chỉ máy chủ, tên cơ sở dữ liệu, người dùng và mật khẩu.

public class Database: DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
        optionsBuilder
            .UseSqlServer("Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;");
}

Kết nối SQL Server với port

Một trong những khó chịu lớn nhất trong cuộc sống là SQL Server lựa chọn sử dụng dấu phẩy (,) làm dấu phân tách cổng thay vì dấu hai chấm (:) như thường thấy. Do đó, các cổng có thể thay đổi tùy thuộc vào môi trường lưu trữ. Một ví dụ điển hình là SQL Server triển khai bên trong container Docker.

public class Database: DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
        optionsBuilder
            // change the port number
            .UseSqlServer("Server=myServerAddress,11433;Database=myDataBase;User Id=myUsername;Password=myPassword;");
}

Kết nối LocalDB của SQL Server

LocalDB vẫn phổ biến trong số các nhà phát triển đang phát triển sản phẩm cục bộ trong môi trường Windows. LocalDB sử dụng công cụ cơ sở dữ liệu SQL Express và cho phép người dùng quản lý và tạo các phiên bản cơ sở dữ liệu mà không gặp rắc rối thêm khi thiết lập một máy chủ mới mỗi lần.

Đảm bảo rằng tên phiên bản khớp với tên phiên bản được cài đặt cục bộ của bạn. Trong ví dụ dưới đây, tên của cài đặt LocalDB của chúng tôi là v11.0, nhưng điều này có thể khác trong môi trường phát triển của bạn.

public class Database: DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
        optionsBuilder
            .UseSqlServer("Server=(localdb)\v11.0;Initial Catalog=myDataBase;Integrated Security=true;");
}

Trình cung cấp dữ liệu SQLite

Theo tôi, SQLite là tùy chọn cơ sở dữ liệu linh hoạt nhất trong danh sách cơ sở dữ liệu trong bài viết này. Cơ sở dữ liệu có thể chạy hoàn toàn từ một trình điều khiển gốc trên nhiều nền tảng.

Trước khi thiết lập chuỗi kết nối cho cơ sở dữ liệu SQLite của chúng ta, chúng ta cần cài đặt gói Nuget Microsoft.EntityFrameworkCore.Sqlite.

Kết nối chuẩn SQLite

Không giống như các chuỗi kết nối cơ sở dữ liệu khác, SQLite tương đối đơn giản. Chúng ta chỉ cần Data Source và đường dẫn đến tệp cơ sở dữ liệu SQLite của chúng ta. Tất nhiên, có những cài đặt khác, nhưng chúng thường không cần thiết khi sử dụng EF Core.

public class Database: DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
        optionsBuilder
            .UseSqlite("Data Source=database.db");
}

Bảo vệ SQLite bằng mật khẩu

Nếu chúng ta lưu trữ thông tin nhạy cảm trong cơ sở dữ liệu SQLite của mình, chúng ta có thể thêm mật khẩu để truy cập cơ sở dữ liệu. Việc bảo vệ bằng mật khẩu ngăn các tiến trình khác tìm thấy cơ sở dữ liệu của chúng ta và thay đổi dữ liệu mà không có sự đồng ý của chúng ta.

public class Database: DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
        optionsBuilder
            .UseSqlite("Data Source=database.db;Password=securePassword");
}

Chuỗi kết nối SQLite trong bộ nhớ

Entity Framework Core có một trình cung cấp cơ sở dữ liệu trong bộ nhớ (in-memory), nó sử dụng LINQ to Objects. Do đó, bất kỳ code nào chạy trên trình cung cấp cơ sở dữ liệu trong bộ nhớ sẽ khác khi chạy với trình cung cấp cơ sở dữ liệu khác.

Khi sử dụng SQLite, chúng ta có thể chạy trình cung cấp cơ sở dữ liệu trong bộ nhớ đồng thời cũng sử dụng cùng một công cụ để ghi vào đĩa. Tính năng SQLite này có lợi thế rõ ràng so với trình cung cấp bộ nhớ trong EF Core được tích hợp sẵn vì chúng ta có thể ghi vào đĩa khi đã sẵn sàng hoặc chúng ta có thể sử dụng phiên bản SQLite trong bộ nhớ để kiểm tra nhanh hơn.

public class Database : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
        optionsBuilder
            .UseSqlite(SqliteInMemoryDatabase.Connection);
}

public static class SqliteInMemoryDatabase
{
    private static object key = new();
    static SqliteInMemoryDatabase()
    {
        lock (key)
        {
            Connection = new SqliteConnection("Filename=:memory:");
            // We want to keep the connection open
            // and reuse it since our database is in-memory
            // Warning: don't use this with multiple clients
            // and closing the connection destroy the database
            Connection.Open();
        }
    }
    
    public static SqliteConnection Connection { get; }
}

Cách tiếp cận này chỉ nên được sử dụng với một ứng dụng khách hoặc trong các tình huống thử nghiệm. Tất cả các phiên bản DbContext sẽ chia sẻ cùng một kết nối.

Trong ví dụ sau, chúng ta có hai instance của Database với một thực thể Person. Chúng ta có thể nạp dữ liệu cho cơ sở dữ liệu trong bộ nhớ, hủy instance đầu tiên, sau đó đọc dữ liệu từ instance thứ hai.

using (var loader = new Database())
{
    var people = new Faker<Person>()
        .Rules((f, p) => p.Name = f.Person.FullName)
        .Generate(100);

    await loader.Database.MigrateAsync();

    await loader.People.AddRangeAsync(people);
    await loader.SaveChangesAsync();
    loader.ChangeTracker.Clear();
}

using (var database = new Database())
{
    var results = await database.People.Take(10).ToListAsync();
    foreach (var result in results)
    {
        Console.WriteLine(result.Name);
    }
}

Trình cung cấp dữ liệu PostgreSQL

PostgreSQL là cơ sở dữ liệu dựa trên máy chủ linh hoạt nhất mà các nhà phát triển .NET có thể sử dụng khi xây dựng ứng dụng. Ngoài các tính năng của cơ sở dữ liệu quan hệ, các nhà phát triển .NET có quyền truy cập vào tìm kiếm toàn văn, các tính năng JSON, thông báo thời gian thực và hơn thế nữa.

Để bắt đầu sử dụng PostgreSQL với Entity Framework Core, chúng ta cần cài đặt gói nuget Npgsql.EntityFrameworkCore.PostgreSQL.

Kết nối chuẩn PostgreSQL

Một chuỗi kết nối PostgreSQL chuẩn trông rất giống với một chuỗi kết nối SQL Server.

public class Database: DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseNpgsql("Host=my_host;Database=my_db;Username=my_user;Password=my_pw");
}

Kết nối PostgreSQL với port

Không giống như chuỗi kết nối SQL Server, cổng là một cờ độc lập được chuyển vào chuỗi kết nối.

public class Database: DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseNpgsql("Host=my_host;Database=my_db;Port=5432;Username=my_user;Password=my_pw");
}

Trình cung cấp dữ liệu MySQL

MySQL phổ biến với những người có nền tảng PHP và vẫn là cơ sở dữ liệu được sử dụng nhiều nhất trên thế giới. MySQL và MariaDB chia sẻ giao diện và cú pháp tương tự, và trong hầu hết các trường hợp, MariaDB là bản thay thế cho MySQL.

Để sử dụng MySQL với EF Core, chúng tôi sẽ cần cài đặt trình cung cấp cơ sở dữ liệu Pomelo.EntityFrameworkCore.MySQL. Có các trình cung cấp cơ sở dữ liệu MySQL khác, nhưng trình cung cấp do Pomelo phát triển được khuyến nghị trong tài liệu chính thức của Microsoft.

Kết nối chuẩn MySQL

Trình cung cấp dữ liệu Pomelo hỗ trợ cả MySQL và MariaDB và điều này có nghĩa là chúng ta cần cho nó biết cơ sở dữ liệu nào chúng ta đang sử dụng thông qua một trong hai phương thức MySqlServerVersion hoặc MariaDbServerVersion.

public class Database: DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        var serverVersion = new MySqlServerVersion(new Version(8, 0, 21));
        optionsBuilder.UseMySql(
            "Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;",
            serverVersion
        );
    }
}

Thiết lập ASP.NET Core cho tất cả các trình cung cấp dữ liệu

Chúng ta đã thấy quá tải phương thức OnConfiguring trong DbContext, nhưng tùy chọn cấu hình này có thể không đủ linh hoạt cho nhu cầu của chúng ta. Vì vậy, thay vào đó, khi chúng ta sử dụng ASP.NET Core, chúng ta có thể tận dụng interface IConfiguration tích hợp sẵn để lấy dữ liệu chuỗi kết nối từ các trình cung cấp cấu hình của chúng ta.

Dưới đây, chúng ta sẽ xem một ví dụ về việc cấu hình các tùy chọn cho EF Core bằng phương thức AddDbContext bên trong ConfigureServices. Lưu ý rằng nếu lớp DbContext của chúng ta đã triển khai OnConfiguring, ASP.NET Core sẽ gọi cả hai phương thức cấu hình, một phương thức trong lớp Startup của chúng ta và một phương thức DbContext triển khai.

public IConfiguration Configuration { get; }

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<Database>(options =>
    {
        var connectionString = 
            Configuration.GetConnectionString("sql");

        // change your database provider here
        options.UseSqlite(connectionString);
    });
}

Chúng ta sẽ cần phải sửa đổi lớp DbContext của mình để có một phương thức khởi tạo chấp nhận DbContextOptions<T>. Hàm khởi tạo bổ sung cho phép ASP.NET Core đưa vào cấu hình của chúng ta.

public class Database: DbContext
{
   public Database(DbContextOptions<Database> options)
     : base(options)
   {
   }
}

Phần kết luận

Entity Framework Core đã trải qua một chặng đường dài từ việc chỉ hỗ trợ Microsoft SQL Server. Có nhiều trình cung cấp dữ liệu, nhưng bài viết này cố gắng chỉ cho bạn cách cấu hình một số cơ sở dữ liệu phổ biến nhất trong hệ sinh thái .NET.

Nếu bạn cần thêm thông tin về trình cung cấp dữ liệu, vui lòng kiểm tra các trang web NuGet Package cho từng gói được đề cập và truy cập trang GitHub của các tác giả.

Như mọi khi, cảm ơn vì đã đọc.

Entity Framework Core
Bài Viết Liên Quan:
Cấu hình trong Entity Framework Core
Trung Nguyen 03/04/2021
Cấu hình trong Entity Framework Core

Trong hướng dẫn này, bạn sẽ tìm hiểu cách cấu hình sử dụng attribute, Fluent API để ghi đè các quy ước mặc đình trong Entity Framework Core.

Các quy ước trong Entity Framework Core
Trung Nguyen 03/04/2021
Các quy ước trong Entity Framework Core

Bạn sẽ tìm hiểu các quy ước được tính hợp sẵn trong Entity Framework Core để tạo khóa chính, khóa ngoại, bảng, lược đồ, cột, kiểu dữ liệu, index ...

Quản lý mối quan hệ Một - Nhiều trong Entity Framework Core
Trung Nguyen 03/04/2021
Quản lý mối quan hệ Một - Nhiều trong Entity Framework Core

Trong hướng dẫn này, bạn sẽ tìm hiểu cách tạo, sửa đổi và xóa mối quan hệ một - nhiều trong Entity Framework Core.

Giới thiệu về các mối quan hệ trong Entity Framework Core
Trung Nguyen 03/04/2021
Giới thiệu về các mối quan hệ trong Entity Framework Core

Trong hướng dẫn này, bạn sẽ tìm hiều về các mối quan hệ một - nhiều, nhiều - nhiều và một - một trong Entity Framework Core.