[ASP.NET for Beginner] - Part 2 - Connect Database and Model Binding

Ở phần trước bạn đã có một khái niệm cơ bản về mô hình MVC. Dựa vào đó, chúng ta sẽ tiếp tục tìm hiểu thêm về database những vấn đề liên quan nhé.

Xem các bài viết trong series

Table of Contents

Có thể hiểu database là trái tim của ứng dụng, còn asp.net là bộ não. Thiết kế một database cho đúng chuẩn thì đòi hỏi kha khá thời gian học + luyện tập thì nó mới lên trình được.

Một cách khác rất hay là bắt tay vào làm một project thực tế. Nếu làm theo phần trước, chắc bạn cũng đã có 1 sample project với tên mvcbasic nhỉ.

Nhìn chung, bạn sẽ có 1 project giống như sau: MVC Basic 0.1 on Github

1. Lựa chọn database

Có hơi bị nhiều hệ quản trị cơ sở dữ liệu đang đấu đá nhau trên thị trường. Ở đây mình sẽ nói sơ qua 1 số loại phổ biến

1.1. SQL Server

Cây nhà là vườn, miễn phí cho người dùng cá nhân, hiệu suất cao, mạnh mẽ, là hệ cơ sở dữ liệu có quan hệ. Sql Server đã chứng minh cho mọi dev thấy tính ổn định của nó.

1.2. The others

Nhìn chung, Microsoft có hỗ trợ kha khá các hệ cơ sở dữ liệu khác như MySQL, PostgreSQL, SQLite, nhưng nếu đã lựa chọn các hệ này, thì bạn sẽ phải tự mày mò kha khá các vấn đề mà đa phần đã được giải quyết khi dùng SQL Server

2. Entity Framework

ASP.NET có một điểm mạnh là Entity Framework (EF). Ở phiên bản core thì nó có thêm EF Core. EF hiểu nôm na là một bộ công cụ cho phép bạn kết nối tới database, truy vấn, thêm xóa sửa vân vân mà không cần phải có kiến thức về cách viết SQL.

Có lợi thì cũng phải có hại, EF theo đánh giá của nhiều người thì nó khá….chậm. Điều này đã và đang được cải thiện rất nhiều ở phiên bản mới đi kèm với ASP.NET Core là Entity Framework Core.

Bạn cần cài đặt

Cài nuget package

Mở project mvcbasic bằng vscode

Lần lượt gõ các lệnh sau trong terminal

dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design

Sau đó, mở file mvcbasic.csproj và thêm dòng sau

<ItemGroup>
  <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>

tiếp tục gõ trong terminal

dotnet restore

3. Tạo Model và Database

Có 2 cách để bắt đầu làm việc với database trong asp.net core là Code first và Database first.

Ngắn gọn thì Code first cho phép bạn viết code trước (tạo các model class), rồi các model bạn tạo sẽ được cập nhật lên database thông qua các migration. Database first thì là cách truyền thống từ xưa tới nay: Tạo database trước, và code của bạn có nghĩa vụ ‘connect’ tới database đó.

Bạn có thể tham khảo thêm ở đây: Code first vs Database first

3.1. Tạo model Phone

chuột phải vào folder Models > new file > Phone.cs

namespace mvcbasic.Models
{
    public class Phone
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

3.2. Tạo Database Context

Database Context có thể hiểu như một công cụ cho phép ứng dụng của bạn kết nối tới Database và thực hiện các tác vụ thêm xóa sửa.

Tạo 1 folder mới ở thư mục gốc với tên ‘Data’

Chuột phải vào folder Data > new file > MvcBasicDbContext.cs

namespace mvcbasic.Data
{
    using Models;
    using Microsoft.EntityFrameworkCore;
 
    public class MvcBasicDbContext : DbContext
    {
        public MvcBasicDbContext(DbContextOptions<MvcBasicDbContext> options) : base(options)
        {
        }
 
        public DbSet<Phone> Phones { get; set; }
    }
}

3.3. Cài đặt Connection String

Để kết nối tới database, thì Entity Framework sẽ cần có các thông tin như username, password, tên database, server đang host cái database này. Tất cả thông số đó đều gộp chung lại thành 1 đoạn string, và giang hồ gọi nó là connection string

Mở file appsettings.json và thêm vào đoạn json sau

"ConnectionStrings" : { "PhoneDbConnectionString": "Server=(localdb)\\\\mssqllocaldb;Database=PhoneDb;Trusted\_Connection=True;" }

Đoạn connection string trên có ý nghĩa như sau Server: LocalDb (là một dạng database local có trên các phiên bản mới của SQL Server) Database: PhoneDb Connection tới database dùng Windows Authentication

Bạn có thể sẽ phải config lại đoạn connection string này cho đúng với môi trường làm việc của bạn

3.4. Cài đặt kết nối

Mở file Startup.cs, tìm method ConfigureServices và thêm vào dòng sau

services.AddDbContext<MvcBasicDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("PhoneDbConnectionString")));

và nhớ add thêm 2 dòng using

using Microsoft.EntityFrameworkCore;
using mvcbasic.Data;

3.5. Tạo Migration đầu tiên

Sau khi tất cả các thao tác chuẩn bị đã hoàn tất, đã tới lúc bạn tạo migration đầu tiên của mình

Trong terminal, gõ

dotnet ef migrations add InitialCreate

VSCode sẽ tự động tạo ra một thư mục tên Migrations, và thêm cơ số file vào đấy

new files

Tiếp tục, gõ

dotnet ef database update

thì những migration này sẽ được thực thi, và database sẽ được tạo ra

database created

Để kiểm tra, bạn có thể dùng Microsoft SQL Server Management Studio với các thông số sau

  • Server Name: (LocalDb)\MSSQLLocalDB
  • Authentication: Windows Authentication

MSSQLLocalDB là tên instance của bạn, có thể khác nếu khi cài SQL Server bạn ko chọn như default

4. Model Binding

Sau khi hoàn tất các bước trên, cơ bản web app của bạn đã có thể kết nối tới database. Nhưng để thực hiện các hành động thêm xóa sửa, thì bạn cần phải có Controller nữa

Bạn có thể tải project hoàn tất ở bước 3 tại đây

4.1. Tạo Controller

VSCode cũng hỗ trợ bạn trong việc tự động tạo ra controller mong muốn mà ko phải code nhiều (thực ra ko phải là VSCode hỗ trợ, mà một công cụ gọi là .NET Cli tools và vài nuget package cho phép bạn làm chuyện này, nhưng trước mắt cứ hiểu vậy đã)

Tên Controller, theo asp.net convention như mình đã nói ở phần 1, sẽ có dạng [Tên]Controller, trong trường hợp này sẽ là PhoneController.

Một quy tắc đặt tên phổ biến là

  • Tên bảng -> số nhiều: Phones
  • Tên model -> số ít: Phone
  • Tên controller: PhoneController
  • Tên view: Create, Delete, Details, Edit và Index

4.2. Các nuget cần thiết

Để có thể tạo controller, bạn sẽ cần thêm một số tool nữa

Mở mvcbasic.csproj và thêm các dòng sau

...
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.2" />
...
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
...

Tổng quan, file csproj sẽ giống như sau

<Project Sdk="Microsoft.NET.Sdk.Web">
 
  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>
 
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.5" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.2" />
  </ItemGroup>
 
  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.1" />
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
  </ItemGroup>
 
</Project>

4.3. Scaffolding

Mở terminal, và gõ lệnh sau

dotnet restore
dotnet build
 
dotnet aspnet-codegenerator controller -name PhoneController -m Phone -dc MvcBasicDbContext --relativeFolderPath Controllers --useDefaultLayout --referenceScriptLibraries

Nhìn vào câu lệnh trên, chắc bạn cũng sẽ đoán được nó làm gì: “Này dotnet, tạo cho tao 1 controller mới tên là PhoneController, dùng model là Phone, Data Context là MvcBasicDbContext, trong folder tên là Controllers, dùng default layout, à có scripts đi kèm nhá”

2 câu lệnh đầu tiên giúp bạn thực sự cài nuget, và build project một phát để đảm bảo ko có lỗi phát sinh, và clear các file tạm ko còn cần thiết

create new controller

gõ tiếp dotnet run để chạy thử app

app with phone controller

bạn có thể vọc vạch các kiểu với các link mà asp.net core tạo sẵn cho bạn, create new, edit, delete, details gì đấy thì tùy

5. Model Binding

Mở file PhoneController ra, bạn sẽ thấy có sẵn code trong đấy rồi, tuy ko đẹp lắm, nhưng nhìn chung là nó chạy tốt

Hãy nhìn vào method Details

// GET: Phone/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }
 
    var phone = await _context.Phones
                              .SingleOrDefaultAsync(m => m.Id == id);
    if (phone == null)
    {
        return NotFound();
    }
 
    return View(phone);
}

Method này nhận một tham số là nullable int có tên là id, khi bạn gọi tới url Phone/Details/5 (như dòng comment ở bên trên), thì số 5 đó sẽ được hiểu là Id. Đó chính là model binding

Tiếp tục, nhìn vào class Create có attribute [HttpPost]

// POST: Phone/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name")] Phone phone)
{
    if (ModelState.IsValid)
    {
        _context.Add(phone);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(phone);
}

Model binding còn vi diệu ở chỗ, nếu bạn dùng hẳn 1 class làm parameter, thì ASP.NET sẽ tự hiểu các property trong class đó, và gắn đúng từng giá trị một

Bạn có thể xóa [Bind("Id,Name")] đi và code vẫn chạy tốt, nhưng như Microsoft đã cảnh báo, để bảo vệ bạn khỏi chuyện orver posting attack, thì bạn phải chỉ định luôn là property nào sẽ được gắn

Method này tương ứng với Views > Phone > Create.cshtml

<!--dòng 17-->
<input asp-for="Name" class="form-control" />

từ khóa asp-for thông báo rằng Name là property sẽ được truyền lên server, và server sẽ “gắn” nó vào model phone của method Create

Tại sao lại ko có Id? Vì Id mặc định được coi như Key của bảng Phone, và key thì ko cần phải có khi tạo mới, vì database sẽ tự sinh ra nó

Tiếp tục, mở Views > Phone > Index.cshtml bạn sẽ thấy đoạn code sau

@foreach (var item in Model)
{
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
            <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
            <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
        </td>
    </tr>
}

ô lạ chưa, có foreach trong html Ngôn ngữ này gọi là Razor, cho phép bạn thực thi một số đoạn code C# trong html, giúp cho việc render ra các tag html như mong muốn.

Razor thông minh tới mức nó tự hiểu chỗ nào là code html, và chỗ nào là code Razor, với các nguyên tắc vô cùng đơn giản

  • Mỗi đoạn code razor đều bắt đầu bằng dấu @
  • Ngay sau dấu { hoặc ( thì ko cần @

Database và Model binding còn nhiều điều để nói. Tạm thời ta cứ hiểu vậy đã

Đón đọc phần 3 bạn nhé 😃