Chuyển đến nội dung chính

Umbraco 13: Quản lý thay đổi Database với MigrationPlan và NPoco - Day 7

Ở Day 6, chúng ta đã thiết kế database đa ngôn ngữ cho hệ thống quản lý Category, sử dụng ba bảng Languages, Categories và CategoryTranslations.

Tuy nhiên, khi ứng dụng phát triển, cấu trúc database thường xuyên thay đổi. Chẳng hạn:

  • Bổ sung cột SortOrder để sắp xếp Category.
  • Tạo bảng CategoryAuditLogs để lưu lịch sử thao tác trên Category.
  • Triển khai phiên bản mới lên môi trường Development, Staging hoặc Production mà không phải tự chạy SQL thủ công trên từng database.

Nếu mỗi lần thay đổi chúng ta đều mở SQL Server Management Studio rồi chạy script bằng tay, việc triển khai sẽ dễ sai sót và khó kiểm soát.

Trong bài này, chúng ta sẽ tìm hiểu cách sử dụng MigrationPlan và MigrationBase của Umbraco 13 để quản lý các thay đổi schema database theo từng bước.

1. Migration là gì?

Migration là một bước thay đổi cấu trúc database có thể được thực thi theo trình tự. Ví dụ, database ban đầu có bảng Categories, sau đó chúng ta cần thêm cột SortOrder, rồi tạo bảng mới để ghi lại lịch sử thay đổi.

Thay vì thực hiện tất cả bằng tay, chúng ta mô tả các bước này trong code.

flowchart TD
    A["Database hiện tại"] --> B["Migration 1: Thêm SortOrder"]
    B --> C["Migration 2: Tạo CategoryAuditLogs"]
    C --> D["Database sau nâng cấp"]

Trong Umbraco, các thành phần chính gồm:

  • MigrationBase: lớp cơ sở để viết logic thay đổi database.
  • MigrationPlan: định nghĩa các bước migration và trạng thái đích.
  • Upgrader: thực thi kế hoạch migration và kiểm tra trạng thái đã chạy.
  • ICoreScopeProvider, IMigrationPlanExecutor và IKeyValueService: các dịch vụ được sử dụng để chạy và theo dõi migration.

2. Nhắc lại database từ Day 6

Để thống nhất ví dụ xuyên suốt series, chúng ta tiếp tục sử dụng ba bảng đã thiết kế ở Day 6.

BảngVai trò
LanguagesLưu danh sách ngôn ngữ như vi-VN, en-US.
CategoriesLưu dữ liệu Category không phụ thuộc ngôn ngữ.
CategoryTranslationsLưu tên và mô tả Category theo từng ngôn ngữ.

Ví dụ, một Category có thể có bản dịch tiếng Việt và tiếng Anh:

erDiagram
    Categories ||--o{ CategoryTranslations : has
    Languages ||--o{ CategoryTranslations : uses

    Categories {
        int Id PK
        string Code
        bit IsActive
    }

    Languages {
        int Id PK
        string Code
        string Name
    }

    CategoryTranslations {
        int CategoryId PK, FK
        int LanguageId PK, FK
        string Name
        string Description
    }

Ở Day 7, chúng ta sẽ bổ sung hai thay đổi:

  1. Thêm cột SortOrder vào bảng Categories.
  2. Tạo bảng CategoryAuditLogs để lưu các sự kiện liên quan đến Category.

Lưu ý về schema: các ví dụ dưới đây giả định database đã có ba bảng trên và cột Categories.Id là khóa chính kiểu số nguyên. Nếu schema thực tế của bạn khác, hãy điều chỉnh migration tương ứng trước khi chạy.

3. Migration 1: Thêm cột SortOrder

Giả sử ban đầu bảng Categories có các cột:

ColumnÝ nghĩa
IdKhóa chính.
CodeMã Category.
IsActiveTrạng thái hoạt động.

Bây giờ chúng ta muốn bổ sung SortOrder để điều khiển thứ tự hiển thị Category.

Ví dụ dữ liệu sau khi bổ sung:

IdCodeSortOrder
1TECH1
2NEWS2
3GUIDE3

Tạo file Migrations/AddCategorySortOrder.cs:

using Umbraco.Cms.Infrastructure.Migrations;

namespace MyProject.Migrations;

public class AddCategorySortOrder : MigrationBase
{
    public AddCategorySortOrder(IMigrationContext context)
        : base(context)
    {
    }

    protected override void Migrate()
    {
        if (!ColumnExists("Categories", "SortOrder"))
        {
            Alter.Table("Categories")
                .AddColumn("SortOrder")
                .AsInt32()
                .NotNullable()
                .WithDefaultValue(0)
                .Do();
        }
    }
}

Giải thích:

  • MigrationBase là lớp cơ sở dành cho migration.
  • ColumnExists() giúp kiểm tra cột trước khi thêm.
  • Alter.Table() mô tả thay đổi trên bảng hiện có.
  • WithDefaultValue(0) đặt giá trị mặc định bằng 0 cho cột mới.
  • Do() thực thi biểu thức migration.

Việc kiểm tra cột giúp migration tránh cố thêm lại cột trong trường hợp schema đã có sẵn. Tuy nhiên, điều đó không thay thế việc quản lý đúng trạng thái migration. Migration đã được triển khai cần được giữ nguyên, không chỉnh sửa tùy tiện sau này.

4. Migration 2: Tạo bảng CategoryAuditLogs

Tiếp theo, chúng ta tạo bảng CategoryAuditLogs để ghi lại các sự kiện như tạo, cập nhật hoặc vô hiệu hóa Category.

Schema dự kiến:

ColumnÝ nghĩa
IdKhóa chính tự tăng.
CategoryIdCategory liên quan đến sự kiện.
ActionLoại thao tác, ví dụ Created hoặc Updated.
CreatedDateThời điểm ghi nhận.

Tạo file Migrations/AddCategoryAuditLogs.cs:

using NPoco;
using Umbraco.Cms.Infrastructure.Migrations;
using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations;

namespace MyProject.Migrations;

public class AddCategoryAuditLogs : MigrationBase
{
    public AddCategoryAuditLogs(IMigrationContext context)
        : base(context)
    {
    }

    protected override void Migrate()
    {
        if (!TableExists("CategoryAuditLogs"))
        {
            Create.Table<CategoryAuditLogSchema>().Do();

            Create.ForeignKey("FK_CategoryAuditLogs_Categories")
                .FromTable("CategoryAuditLogs")
                .ForeignColumn("CategoryId")
                .ToTable("Categories")
                .PrimaryColumn("Id")
                .Do();
        }
    }

    [TableName("CategoryAuditLogs")]
    [PrimaryKey("Id", AutoIncrement = true)]
    [ExplicitColumns]
    public class CategoryAuditLogSchema
    {
        [PrimaryKeyColumn(
            AutoIncrement = true,
            IdentitySeed = 1)]
        [Column("Id")]
        public int Id { get; set; }

        [Column("CategoryId")]
        public int CategoryId { get; set; }

        [Column("Action")]
        [Length(50)]
        public string Action { get; set; } = string.Empty;

        [Column("CreatedDate")]
        public DateTime CreatedDate { get; set; }
    }
}

Đoạn code sử dụng các annotation của NPoco để mô tả schema:

  • [TableName] chỉ định tên bảng trong database.
  • [PrimaryKey] xác định khóa chính và việc tự tăng.
  • [ExplicitColumns] yêu cầu khai báo rõ các cột.
  • [Column] ánh xạ property sang tên cột.

Migration tạo bảng và bổ sung foreign key từ CategoryAuditLogs.CategoryId đến Categories.Id.

Ở ví dụ thực tế, nên kiểm tra rằng cột được tham chiếu có kiểu dữ liệu tương thích, khóa chính đã tồn tại và migration chạy trên đúng database. Nếu bảng audit cần giữ lịch sử ngay cả sau khi Category bị xóa, bạn cũng cần thiết kế chính sách xóa phù hợp, thay vì mặc định xóa dây chuyền các bản ghi lịch sử.

Phân biệt schema class và model nghiệp vụ: CategoryAuditLogSchema chỉ mô tả cấu trúc bảng tại thời điểm migration. Không nên dùng trực tiếp class này làm DTO hoặc model dùng cho toàn bộ nghiệp vụ. Migration cần giữ ổn định để những lần triển khai sau có thể tái hiện đúng các bước lịch sử.

5. Tạo MigrationPlan

Chúng ta đã có hai migration. Bước tiếp theo là khai báo thứ tự thực thi bằng MigrationPlan.

Tạo file Migrations/CategoryDatabaseMigrationPlan.cs:

using Umbraco.Cms.Infrastructure.Migrations;

namespace MyProject.Migrations;

public class CategoryDatabaseMigrationPlan : MigrationPlan
{
    public CategoryDatabaseMigrationPlan()
        : base("CategoryDatabase")
    {
        From(string.Empty)
            .To<AddCategorySortOrder>("category-sort-order")
            .To<AddCategoryAuditLogs>("category-audit-logs");
    }
}

Trong đoạn code trên:

  • "CategoryDatabase" là tên riêng của migration plan.
  • From(string.Empty) biểu thị trạng thái ban đầu khi plan chưa có trạng thái migration được ghi nhận.
  • To<AddCategorySortOrder>(...) khai báo bước thêm cột.
  • To<AddCategoryAuditLogs>(...) khai báo bước tạo bảng audit sau bước đầu tiên.

Trình tự được mô tả như sau:

flowchart TD
    A["Chưa chạy plan"] --> B["category-sort-order"]
    B --> C["category-audit-logs"]
    C --> D["Hoàn tất plan"]

Các chuỗi trạng thái như category-sort-order và category-audit-logs là mã trạng thái do chúng ta đặt. Hãy giữ chúng ổn định sau khi đã triển khai ứng dụng.

6. Chạy MigrationPlan khi Umbraco khởi động

Định nghĩa plan thôi chưa đủ; chúng ta còn cần đăng ký cơ chế thực thi. Với Umbraco 13, có thể dùng notification handler cho UmbracoApplicationStartingNotification.

Tạo file Migrations/RunCategoryDatabaseMigration.cs:

using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Migrations;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade;

namespace MyProject.Migrations;

public class RunCategoryDatabaseMigration
    : INotificationHandler<UmbracoApplicationStartingNotification>
{
    private readonly IMigrationPlanExecutor _migrationPlanExecutor;
    private readonly ICoreScopeProvider _coreScopeProvider;
    private readonly IKeyValueService _keyValueService;
    private readonly IRuntimeState _runtimeState;

    public RunCategoryDatabaseMigration(
        IMigrationPlanExecutor migrationPlanExecutor,
        ICoreScopeProvider coreScopeProvider,
        IKeyValueService keyValueService,
        IRuntimeState runtimeState)
    {
        _migrationPlanExecutor = migrationPlanExecutor;
        _coreScopeProvider = coreScopeProvider;
        _keyValueService = keyValueService;
        _runtimeState = runtimeState;
    }

    public void Handle(
        UmbracoApplicationStartingNotification notification)
    {
        if (_runtimeState.Level < RuntimeLevel.Run)
        {
            return;
        }

        var plan = new CategoryDatabaseMigrationPlan();
        var upgrader = new Upgrader(plan);

        upgrader.Execute(
            _migrationPlanExecutor,
            _coreScopeProvider,
            _keyValueService);
    }
}

Đoạn handler thực hiện các công việc sau:

  1. Kiểm tra runtime state để không chạy migration khi Umbraco chưa ở trạng thái cho phép.
  2. Tạo CategoryDatabaseMigrationPlan.
  3. Tạo Upgrader để thực thi plan.
  4. Truyền các dịch vụ cần thiết để Umbraco thực thi migration và theo dõi trạng thái.

Đăng ký handler trong một composer. Tạo file Migrations/CategoryDatabaseMigrationComposer.cs:

using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Notifications;

namespace MyProject.Migrations;

public class CategoryDatabaseMigrationComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.AddNotificationHandler<
            UmbracoApplicationStartingNotification,
            RunCategoryDatabaseMigration>();
    }
}

Umbraco sẽ phát notification khi ứng dụng khởi động, từ đó handler gọi migration plan. Khi plan đã ở trạng thái mới nhất, Umbraco có thể xác định không còn bước nào cần thực thi.

Ví dụ này dùng notification handler theo hướng dẫn dành cho Umbraco 13. Nếu dự án của bạn đã có cơ chế chạy migration bằng Component hoặc một cơ chế khởi động khác, hãy chọn một cách phù hợp và tránh đăng ký hai nơi cùng chạy một plan.

7. MigrationPlan lưu trạng thái ở đâu?

Umbraco cần biết migration nào đã chạy để không thực hiện lại toàn bộ các bước mỗi lần ứng dụng khởi động.

Trạng thái migration plan được Umbraco theo dõi thông qua dịch vụ IKeyValueService, với dữ liệu được lưu trong bảng hệ thống umbracoKeyValue.

Điều này giúp phân biệt hai khái niệm:

  • Schema database: các bảng, cột, khóa chính và khóa ngoại thực tế.
  • Migration state: trạng thái mà migration plan đã ghi nhận.

Hai thứ này cần nhất quán. Nếu bạn tự xóa bảng hoặc chỉnh sửa schema trong SQL Server nhưng giữ nguyên trạng thái migration, Umbraco có thể cho rằng bước đó đã hoàn thành và không chạy lại.

Vì vậy, không nên tùy tiện xóa hoặc chỉnh sửa bản ghi trong umbracoKeyValue để ép migration chạy lại. Khi thử nghiệm, hãy dùng database Development có thể khôi phục hoặc tạo lại, đồng thời kiểm tra schema trước và sau khi chạy.

8. Kiểm tra kết quả

Sau khi build dự án và khởi động Umbraco, hãy kiểm tra database bằng SQL Server Management Studio.

Kiểm tra cột SortOrder:

SELECT
    Id,
    Code,
    SortOrder
FROM Categories
ORDER BY SortOrder, Id;

Kiểm tra cấu trúc bảng audit:

SELECT
    COLUMN_NAME,
    DATA_TYPE,
    IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'CategoryAuditLogs'
ORDER BY ORDINAL_POSITION;

Kiểm tra foreign key:

SELECT
    fk.name AS ForeignKeyName,
    OBJECT_NAME(fk.parent_object_id) AS TableName,
    COL_NAME(
        fkc.parent_object_id,
        fkc.parent_column_id
    ) AS ColumnName,
    OBJECT_NAME(fk.referenced_object_id) AS ReferencedTable,
    COL_NAME(
        fkc.referenced_object_id,
        fkc.referenced_column_id
    ) AS ReferencedColumn
FROM sys.foreign_keys AS fk
INNER JOIN sys.foreign_key_columns AS fkc
    ON fk.object_id = fkc.constraint_object_id
WHERE OBJECT_NAME(fk.parent_object_id) = 'CategoryAuditLogs';

Nếu migration chạy thành công, bạn sẽ thấy cột SortOrder, bảng CategoryAuditLogs và foreign key đến Categories.

9. Rollback Migration trong môi trường Development

Trong quá trình phát triển, đôi khi chúng ta muốn quay về trạng thái database trước khi chạy migration để thử lại từ đầu.

Ví dụ, sau khi chạy CategoryDatabaseMigrationPlan, database đã có:

  • Cột SortOrder trong bảng Categories.
  • Bảng CategoryAuditLogs và các bản ghi audit dùng để thử nghiệm.
  • Trạng thái migration đã được lưu trong bảng umbracoKeyValue.

Nếu chỉ xóa bảng và cột nhưng giữ nguyên trạng thái migration, Umbraco có thể cho rằng migration đã hoàn thành và không chạy lại các bước đó. Ngược lại, nếu chỉ xóa trạng thái migration mà không khôi phục schema, lần chạy tiếp theo có thể gặp lỗi vì các bảng hoặc cột đã tồn tại.

Vì vậy, khi cần reset hoàn toàn migration trong Development, chúng ta phải xử lý cả dữ liệu, schema và trạng thái migration.

9.1. Thứ tự rollback

flowchart TD
    A["Dừng ứng dụng Umbraco"] --> B["Kiểm tra dữ liệu cần giữ"]
    B --> C["Xóa dữ liệu thử nghiệm"]
    C --> D["Xóa bảng CategoryAuditLogs"]
    D --> E["Xóa cột Categories.SortOrder"]
    E --> F["Xóa trạng thái CategoryDatabase"]
    F --> G["Khởi động Umbraco"]
    G --> H["Migration chạy lại"]

Hãy dừng ứng dụng trước khi thao tác trực tiếp trên database để tránh migration chạy đồng thời với script rollback.

9.2. Xóa dữ liệu thử nghiệm

Nếu đã insert dữ liệu thử nghiệm vào CategoryAuditLogs, hãy xóa dữ liệu đó trước khi xóa bảng.

DELETE FROM dbo.CategoryAuditLogs;

Trong ví dụ này, toàn bộ bảng audit sẽ bị xóa dữ liệu. Chỉ chạy lệnh trên khi chắc chắn đây là database Development và bạn không cần giữ các bản ghi đó.

Nếu migration còn insert dữ liệu mẫu vào các bảng Categories, Languages hoặc CategoryTranslations, hãy xóa đúng các bản ghi do migration tạo ra bằng điều kiện nhận diện cụ thể. Không nên xóa toàn bộ dữ liệu của ba bảng này nếu chúng đã có dữ liệu từ Day 6.

9.3. Xóa bảng và cột đã được tạo

Sau khi xử lý dữ liệu thử nghiệm, xóa bảng CategoryAuditLogs và cột SortOrder.

IF OBJECT_ID(
    N'dbo.CategoryAuditLogs',
    N'U'
) IS NOT NULL
BEGIN
    DROP TABLE dbo.CategoryAuditLogs;
END;

IF COL_LENGTH(
    N'dbo.Categories',
    N'SortOrder'
) IS NOT NULL
BEGIN
    ALTER TABLE dbo.Categories
    DROP COLUMN SortOrder;
END;

Khi xóa bảng CategoryAuditLogs, foreign key nằm trong bảng đó cũng bị xóa theo. Cột SortOrder sẽ không còn tồn tại sau lệnh ALTER TABLE ... DROP COLUMN.

Lưu ý: nếu bạn đã thêm các index, constraint hoặc đối tượng database riêng khác liên quan đến cột SortOrder, hãy xóa các đối tượng phụ thuộc trước khi xóa cột.

9.4. Xóa trạng thái MigrationPlan trong umbracoKeyValue

Migration plan được theo dõi qua IKeyValueService. Với plan có tên CategoryDatabase, key trạng thái thông thường có dạng:

Umbraco.Core.Upgrader.State+CategoryDatabase

Trước khi xóa key, hãy truy vấn để kiểm tra giá trị thực tế trong database của dự án:

SELECT [key], [value]
FROM dbo.umbracoKeyValue
WHERE [key] LIKE
    N'Umbraco.Core.Upgrader.State+CategoryDatabase%';

Nếu đã xác nhận đúng key của plan cần reset, có thể xóa riêng key đó:

DELETE FROM dbo.umbracoKeyValue
WHERE [key] =
    N'Umbraco.Core.Upgrader.State+CategoryDatabase';

Không xóa toàn bộ dữ liệu trong umbracoKeyValue. Bảng này còn lưu các giá trị quan trọng khác của Umbraco, không chỉ trạng thái migration của ứng dụng.

9.5. Script rollback tổng hợp

Trong môi trường Development, nếu muốn thực hiện rollback theo một quy trình có thể kiểm soát, có thể gom các thao tác vào một transaction như dưới đây. Script giả định bảng và cột được tạo theo ví dụ của bài viết, và không có đối tượng phụ thuộc khác cần xử lý.

BEGIN TRY
    BEGIN TRANSACTION;

    -- 1. Xóa dữ liệu thử nghiệm trong bảng audit.
    IF OBJECT_ID(
        N'dbo.CategoryAuditLogs',
        N'U'
    ) IS NOT NULL
    BEGIN
        DELETE FROM dbo.CategoryAuditLogs;
    END;

    -- 2. Xóa bảng audit.
    IF OBJECT_ID(
        N'dbo.CategoryAuditLogs',
        N'U'
    ) IS NOT NULL
    BEGIN
        DROP TABLE dbo.CategoryAuditLogs;
    END;

    -- 3. Xóa cột đã thêm bởi migration.
    IF COL_LENGTH(
        N'dbo.Categories',
        N'SortOrder'
    ) IS NOT NULL
    BEGIN
        ALTER TABLE dbo.Categories
        DROP COLUMN SortOrder;
    END;

    -- 4. Xóa trạng thái của đúng migration plan.
    DELETE FROM dbo.umbracoKeyValue
    WHERE [key] =
        N'Umbraco.Core.Upgrader.State+CategoryDatabase';

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;

    THROW;
END CATCH;

Transaction giúp các thao tác SQL được commit cùng nhau hoặc rollback khi có lỗi. Tuy nhiên, trước khi chạy, hãy kiểm tra chính xác tên bảng, tên cột, key migration và các đối tượng phụ thuộc trong database thực tế.

9.6. Khởi động lại và kiểm tra

Sau khi script hoàn tất:

  1. Khởi động lại Umbraco.
  2. Để notification handler thực thi CategoryDatabaseMigrationPlan.
  3. Kiểm tra cột SortOrder đã được tạo lại.
  4. Kiểm tra bảng CategoryAuditLogs và foreign key đã tồn tại.
  5. Kiểm tra trạng thái migration đã được ghi nhận lại.

Nếu migration chạy thành công, database sẽ trở về trạng thái sau khi chạy đầy đủ migration, nhưng các dữ liệu thử nghiệm đã xóa sẽ không tự động được phục hồi.

9.7. Có nên dùng cách này trong Production?

Không nên. Quy trình trên dành cho việc reset migration trong Development. Trong Production, cách tiếp cận an toàn hơn là viết một migration mới để thay đổi hoặc hoàn tác schema theo kế hoạch, bảo toàn dữ liệu cần thiết và kiểm tra trên bản sao database trước khi triển khai.

Umbraco MigrationPlan không tự cung cấp một phương thức Down() tự động tương đương EF Core Migrations. Việc hoàn tác phải được thiết kế rõ ràng. Đặc biệt, không nên xóa trạng thái migration trong Production chỉ để ép Umbraco chạy lại các bước cũ.

10. Lưu ý quan trọng: MigrationPlan và EF Core Migrations

Ở Day 6, chúng ta có đề cập đến EF Core khi làm việc với database tùy chỉnh. Trong khi đó, Day 7 sử dụng migration system của Umbraco và NPoco.

Đây là hai cơ chế khác nhau:

Cơ chếMục đích
EF Core MigrationsQuản lý thay đổi schema theo migration của EF Core.
Umbraco MigrationPlan + NPocoQuản lý các bước migration thông qua hệ thống migration của Umbraco.

Nguyên tắc quan trọng: không nên để cả EF Core Migrations và Umbraco MigrationPlan cùng quản lý thay đổi schema của cùng một bảng mà không có quy ước rõ ràng. Hai hệ thống có lịch sử và trạng thái riêng; chúng không tự đồng bộ trạng thái với nhau.

Đối với series này, phần Day 7 minh họa cách chuyển sang dùng Umbraco MigrationPlan cho các thay đổi schema mới. Nếu dự án của bạn đã sử dụng EF Core Migrations để quản lý các bảng Categories và CategoryTranslations, hãy cân nhắc tiếp tục dùng EF Core cho chính các bảng đó, hoặc lập kế hoạch chuyển quyền quản lý một cách rõ ràng. Không chạy ví dụ này trực tiếp trên database hiện có trước khi xác nhận schema và lịch sử migration.

11. Tổng kết

Qua Day 7, chúng ta đã thực hiện các bước:

  • Bổ sung cột SortOrder cho bảng Categories.
  • Tạo bảng CategoryAuditLogs có foreign key đến Categories.
  • Dùng MigrationBase để định nghĩa các thay đổi database.
  • Dùng MigrationPlan để sắp xếp các bước migration theo trạng thái.
  • Dùng Upgrader và notification handler để chạy plan khi Umbraco khởi động.
  • Tìm hiểu vai trò của umbracoKeyValue trong việc lưu trạng thái migration.

Migration không chỉ là cách tạo bảng tự động. Đây còn là cơ chế giúp đội ngũ phát triển quản lý thay đổi database có trình tự, có thể kiểm tra và triển khai nhất quán giữa các môi trường.

Bài tiếp theo

Sau khi đã biết cách quản lý schema database, bước tiếp theo là tìm hiểu cách truy vấn và ghi dữ liệu vào các bảng tùy chỉnh bằng scope và database API của Umbraco, rồi kết nối chúng với API để ứng dụng Next.js có thể sử dụng dữ liệu.

Tài liệu tham khảo

Nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.