22/10/2016

[WPF] Create Simple WPF App With MVVM and Entity Framework Core - Part II


Qua Phần I, với demo đơn giản nhưng bao quát các phần cần có khi làm việc với MVVM rồi. Thực ra mô hình này cơ bản không có gì phức tạp cho người mới bắt đầu. Điều bạn cần biết, WPF sử dụng XAML để định nghĩa giao diện (UWP cũng sử dụng XAML là một trong các lựa chọn) và XAML giúp việc thiết kế giao diện trở nên linh hoạt hơn nhờ cú pháp của nó, cộng với công cụ Blend. XAML sẽ ánh xạ với C#, cho nên cái gì thiết kế trên XAML được thì tất nhiên sử dụng code để thay thế bình thường. Nhưng vậy thì còn gì vui, tốn thời gian, công sức trong khi sử dụng XAML triển khai ý tưởng nhanh hơn nhiều, ngoại trừ một số control bạn chắc chắn cần dùng code để xử lý.

Quay lại MVVM, với việc hỗ trợ Binding ta sử dụng mô hình này giúp mã nguồn sạch hơn, dễ bảo trì, kiểm thử. Bởi vì không có mã nào dưới phần giao diện, toàn bộ code xử lý, ngay cả các hành vi, sự kiện cũng được viết được dưới ViewModel. Trên mạng, các đồng nghiệp viết rất nhiều lợi ích và hạn chế của MVVM bạn có thể tham khảo thêm.



Phần này, tôi thử dùng Entity Framework để thao tác với database, CRUD các kiểu. Entity Framework thì nó có 3 cách tiếp cận, mỗi cách thì thêm kiểu có database hoặc chưa. Vì ta làm từ đầu nên giả sử ta chưa có database và cần tạo mới. Tôi thích sử dụng cách tiếp cận Code First và code toàn bộ, database không có tạo sẵn trên SQL Server. Máy tôi không có cài đặt SQL Server Manager Studio luôn, SQL Server thì chỉ chạy Sql LocalDb đi kèm Visual Studio, trong VS có Sql  Explorer thay thế tạm SQL Server Manager Studio cũng được. Nên dùng Code First tự generate database khi khởi tạo dựa vào Model của ta. Cách này được cho là ưng nhất, nhưng tốn công ngồi gõ.

Thực ra, các ứng dụng quản lý nhỏ, không cần phải sử dụng Entity Framework để xử lý đâu, thật dư sức và tốn kém. Nhưng đây là demo nên ta thử vài phần cơ bản cho vui...

Tham khảo:

Bắt Đầu

Yêu cầu:
  • Visual Studio 2015 Update 3
  • Latest version of NuGet Package Manager
  • Latest version of Windows PowerShell
  • .NET 4.5.1 or later (I'm on .NET 4.6)

Tôi sử dụng các công cụ với version gần đây nhất, nên nếu có thể bạn hãy cài các công cụ mới nhất. Tuy nhiên mọi thứ rất cơ bản nên không có thay đổi đáng quan tâm, bạn có thể linh động sử dụng trong các version thấp hơn.

1. Install Entity Framework

(EF có thể làm việc với nhiều Data Providers khác nhau, trong nội dung mà chúng ta đang làm việc sử dụng SQL Server)

Sử dụng lệnh power shell trong Visual Studio như sau:
(Tool | NuGet Package Manager | Package Manager Console)

RUN:
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools –Pre
Figure 1: Install-Package from Nuget

Chúng ta sẽ cài thêm thư viện EF cho Project Models, chọn như hình trên. Bạn có thể sử dụng giao diện Nuget trực quan để cài đặt hoặc dùng code như đã nói.  (Nếu lỗi ngoài ý muốn, hãy Set as StartUp Project cho Models).

2. Create DataContext Class

Đây là nơi khai báo các model để EF hiểu...

a.) Tạo mới DataContext Class
Add reference: System.Configuration
using Microsoft.EntityFrameworkCore;
using System.Configuration;

namespace DataContext
{
    public class FunniesDataContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["FunniesConnection"].ConnectionString);
            base.OnConfiguring(optionsBuilder);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }

        public DbSet<Models.Department> Departments { get; set; }
        public DbSet<Models.Employee> Employees { get; set; }
    }
}

Connection bạn đặt ở App.config nhé!

b.) Add Migrations and Update Database
(Nên Set as StartUp Project cho Business.Model để tránh trường hợp lỗi khi không chạy được lệnh Migrations)
Run:
Add-Migration Your_Migration_Name
Update-Database

Figure 2.2.1: Add-Migration


Figure 2.2.2: View Database in SQL Server 

* Cứ mỗi lần chạy lệnh Update-Database các thay đổi model sẽ được apply xuống database.
* Bây giờ tôi muốn trong bảng Department có dữ liệu mẫu để test. Vì ta chỉ làm việc với bảng Employees, nên không tạo giao diện nhập dữ liệu cho Department.

OK

- Bạn thêm Migration 2 như sau:
  • Add-Migration Your_Migration_Name (Chạy lệnh này trước)
  • Sau đó bổ sung đoạn lệnh dưới đây vào file Migration mới tạo ở trên (Trong folder Models | Migrations)
protected override void Up(MigrationBuilder migrationBuilder)
{
    ///TODO: Seed data for Departments Table
    migrationBuilder.Sql("INSERT INTO Departments (Id, Name, Phone) VALUES   ('" + Guid.NewGuid() + "','Business', '84123456789')");
    migrationBuilder.Sql("INSERT INTO Departments (Id, Name, Phone) VALUES   ('" + Guid.NewGuid() + "','Development', '84987654321')");
}
  • Update-Database (Chạy tiếp lệnh này để apply migration mới xuống database nhé)
Figure 2.2.3: Add-Migration other

Figure 2.2.4: Update-Database again

3. Implemention Repositories

Trong Project Models tôi sử dụng folder Repositories để chứa code xử lý thao tác với database qua Entity Framework. Sau đó cho phép ViewModels sử dụng...

using System;
using System.Collections.Generic;
using System.Linq;

namespace Models.Repositories
{
    public class EmployeeRepository : IEmployeeRepository
    {
        public static EmployeeRepository Instance { get; } = new EmployeeRepository();

        public IEnumerable<Employee> GetAllEmployee()
        {
            using (var context = new DataContext.FunniesDataContext())
            {
                return context.Employees.ToList();
            }
        }

        public bool InsertEmployee(Guid id, string fullName, int age, string phone, string address, Guid departmentId)
        {
            using (var context = new DataContext.FunniesDataContext())
            {
                var employee = new Employee
                {
                    Id = id,
                    FullName = fullName,
                    Age = age,
                    Phone = phone,
                    Address = address,
                    DepartmentId = departmentId
                };

                context.Employees.Add(employee);

                try
                {
                    // Attempt to save changes to the database
                    context.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        public bool UpdateEmployee(Guid id, string fullName, int age, string phone, string address, Guid departmentId)
        {
            using (var context = new DataContext.FunniesDataContext())
            {

                var employee = context.Employees.Where(_ => _.Id.Equals(id)).FirstOrDefault();

                employee.FullName = fullName;
                employee.Age = age;
                employee.Phone = phone;
                employee.Address = address;
                employee.DepartmentId = departmentId;

                context.Employees.Update(employee);

                try
                {
                    // Attempt to save changes to the database
                    context.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            };
        }

        public bool DeleteEmployee(Guid id)
        {
            using (var context = new DataContext.FunniesDataContext())
            {
                var employee = context.Employees.Where(_ => _.Id.Equals(id)).FirstOrDefault();
                context.Employees.Remove(employee);

                try
                {
                    // Attempt to save changes to the database
                    context.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            };
        }
    }
}

- Get dữ liệu nhớ dùng System.Linq để ToList() hoặc FirstOrDefault() nhé. Xem kĩ trong code trên
- Phần này nó cũng đơn giản, chỉ mới có các hàm CRUD.  Bạn có thể xem thêm trong mã nguồn cuối bài viết này.
- Trong ViewModel bạn khai báo để sử dụng Repository như sau (Chúng ta sử dụng interface để gọi)
- Tôi split file code cho dễ nhìn thôi, các bạn không hiểu thì có thể nhìn số line của code.

Figure 3: Use Repositories


4. Query Data

Database đã khởi tạo xong, giờ ta có thể nhập xuất dữ liệu được rồi
(Nhớ Set as StartUp Project cho Business.App để chạy demo)

(*) Vì ta có các Project tách biệt, nên bạn cần khai báo connectionStrings trong App.Config của các project như nhau (Thật ra project ViewModel không cần khai báo đâu nhé)

Figure 4: Add Connection Strings

OK
- Đến bước này, bạn có thể get dữ liệu lên giao diện rồi.
- Các thao tác thêm, sửa, xóa thông qua command như Phần I, chỉ là phần này làm việc với Database
- Logic thao tác CRUD thì bạn tự tìm hướng phù hợp với mình. Tùy mỗi dự án nó lại khác nhau, tôi chỉ làm mẫu đơn giản thôi.
- Vẫn chưa validate nên nhập sai kiểu dữ liệu, hoặc query hỏng là lỗi đấy nhé, sang phần khác ta sẽ bổ sung. Không nên làm 1 lần rất rối

5. Final

Trong phần này, ta chỉ làm quen cách dùng Entity Framework, tôi dùng phiên bản Entity Framework Core nên hơi khác chút xíu. Nhưng bạn có thể tự nghiên cứu để làm việc với các phiên bản thấp hơn, vì đây chỉ là cơ bản.
Lưu ý: 
Nếu bạn sử dụng source code. Chạy lệnh Update-Database để khởi tạo và chỉnh lại ConnectionString trong App.config




Created: 11/10/2016
Updated: 15/10/2016
Updated: 16/10/2016
Updated: 21/10/2016
Updated: 22/10/2016
Source Code: Tải về tại đây

Share

Happy Reading!

[WPF] Create Simple WPF App With MVVM and Entity Framework Core - Part II
4/ 5
Oleh

Buzz!

Stay updated via email new newsletter

Don't
Use obscene or offensive language.
Personally attack people, their edits, or their comments.
Rant or otherwise harass, abuse, or intimidate others.
Post anything you don't want the world to see. This is a public space.
Infringe copyright.