Sử dụng Entity Framework trong Lập trình .NET

Hướng dẫn sau đây sẽ giúp chúng ta hiểu về Microsoft Entity Framework ADO.Net. Bắt đầu với lý thuyết cơ bản của Entity Framework 4.0 và sau đó là bản demo thực tế của các chức năng quan trọng cùng với mã nguồn. Các bạn cũng có thể tải project demo cùng với cơ sở dữ liệu được sử dụng trong ví dụ của bài viết này.

Kiến trúc Entity Framework (EF)

ADO.NET Entity Framework là một nền tảng được sử dụng để làm việc với database thông qua cơ chế ánh xạ Object/Relational Mapping (ORM). Nhờ đó, bạn có thể truy vấn, thao tác với database gián tiếp thông qua các đối tượng lập trình.

Kiến trúc của Entity Framework được minh họa như sau:

Kiến trúc của Entity FrameworkKiến trúc của Entity Framework

Các nội dung dưới đây sẽ đi vào giải thích từng phần trong sơ đồ trên. Trong giới hạn của bài viết, tôi chỉ đi khái quát để bạn nắm được nội dung chính. Trong thực tế, bạn cũng không cần biết sâu hơn về kiến trúc bên dưới trừ những mục đích đặc biệt.

Object Services

Đây là các class tự động sinh ra tương ứng với mô hình dữ liệu. Các class này bao gồm:

  •  ObjectContext đại diện cho một database. ObjectContext có chức năng quản lý các kết nối, định nghĩa mô hình dữ liệu với metadata và thao tác với database. Lớp này cũng có thể thêm vào các phương thức đại diện cho các stored procedure trong database.
  •  ObjectSet là một một tập hợp các entity. Mỗi đối tượng này tương ứng với một table. Có thể lấy được các đối tượng này thông qua các property tương ứng của ObjectContext.
  •  EntityObject, ComplexObject là các lớp tương ứng cho một dòng dữ liệu của table trong database. Khác biệt chính giữa hai loại này là ComplexObject không chứa primary key.
  •  EntityCollection và EntityReference là các đối tượng thể hiện mối quan hệ (relationship) giữa hai entity class. Mỗi đối tượng này có thể được truy xuất thông qua các property của entity class.
Bảng ánh xạ tương đương sau giữa các đối tượng trong database và EF
Database Object Entity Framework Object
Database ObjectContext
Table, View EntityObject, ComplexObject
Column Property
Relationship EntityCollection<TEntity>, EntityReference<TEntity>
Chi  tiết về các components của Entity FrameworkChi tiết về các components của Entity Framework

EDM (Entity Data Model)

Giúp tạo liên kết và mô tả giữa nguồn dữ liệu vật lý và các đối tượng bussiness (hay object layer) trong ứng dụng. Entity Data Model (EDM) là mô hình dữ liệu được mô tả thông qua các ngôn ngữ theo chuẩn XML. EDM được chia làm 3 lớp là: Conceptual, Mapping và Logical (Storage Model). Mỗi lớp này được định nghĩa bởi ngôn ngữ riêng theo định dạng XML

Entity Data ModelEntity Data Model

  •  Conceptual – Conceptual Schema Definition Language (CSDL) là ngôn ngữ định nghĩa các entity, relationship, hàm trong tập tin với phần mở rộng .csdl. Có thể tạo được các entity class (object layer).
  •  Mapping – Mapping specification language (MSL) định nghĩa các ánh xạ giữa lớp conceptual và logical, nội dung này được lưu trong tập tin .msl.
  •  Logical – Store Schema Definition Language (SSDL) định nghĩa mô hình lưu trữ của dữ liệu, lưu trữ trong tập tin .ssdl.

LINQ to Entities

là ngôn ngữ truy vấn được sử dụng trong EF. Nó trả về các entites được định nghĩa trong storage model.

Entity SQL

nó cũng là ngôn ngữ truy vấn dữ liệu tương tự Linq To Entities.

Object Service

object service is a main entry point for accessing data from database and to return it back. Object service is responsible for materialization which is process of converting data returned from entity client data provider (next layer) to an entity object structure.

LINQ to Entities

là ngôn ngữ truy vấn được sử dụng trong EF. Nó trả về các entites được định nghĩa trong storage model.

Entity SQL

nó cũng là ngôn ngữ truy vấn dữ liệu tương tự Linq To Entities.

Object Service

object service is a main entry point for accessing data from database and to return it back. Object service is responsible for materialization which is process of converting data returned from entity client data provider (next layer) to an entity object structure.

Entity Client Data Provider

EntityClient là một data provider mới của ADO.NET dùng để truy xuất đến database. Được xây dựng bên trên các ADO.NET data provider cơ bản, EntityClient không truy xuất trực tiếp dữ liệu mà thông qua các data provider khác dựa vào các thông tin dữ liệu từ Entity Data Model.

EntityClient cũng bao gồm các lớp giống như các ADO.NET data provider khác và tên lớp được đặt với tiền tố Entity. Ví dụ bạn có thể tạo kết nối bằng EntityConnection, tạo các câu truy vấn bằng EntityCommand và đọc kết quả bằng EntityDataReader.

Một điểm khác biệt với các data provider khác là EntityClient sử dụng Entity SQL để truy vấn dữ liệu. Các lệnh Entity SQL sẽ được chuyển thành một cấu trúc lệnh dạng cây (command tree) và chuyển xuống cho các data provider khác.

ADO.Net Data Provider

This layer communicates with database using standard ADO.Net.

Các thao tác cơ bản với EF

Là thành phần trung gian giữa ứng dụng và database, Entity Data Model (EDM) giúp tạo liên kết và mô tả giữa nguồn dữ liệu vật lý và các đối tượng bussiness (hay object layer) trong ứng dụng. Dựa vào sự lựa chọn thành phần nào sẽ được tạo ra trước, một ứng dụng Entity Framework (EF) có thể sử dụng 1 trong 3 cách tiếp cận: Database First, Model First và Code First.

Các sơ đồ dưới đây minh hoạt mối quan hệ và thứ tự tạo ra giữa các thành phần dữ liệu trong ứng dụng của Entity Framework. Phần Model tương ứng với tập tin .edmx, Code tương ứng với tập tin .cs (hoặc .vb nếu bạn dùng VB.NET).

Bạn có thể nhận thấy rằng phần Model luôn được theo sau bởi Code, điều này là nhờ công cụ Entity Data Model Designer trong Visual tự động tạo ra code tương ứng mỗi khi bạn thực hiện chỉnh sửa tập tin .edmx

Database First

Đây là cách thông thường và được hỗ trợ từ phiên bản EF 1 trong Visual Studio 2008. EF sẽ tự động tạo ra data model và các class (object layer) cho bạn từ database có sẵn thông qua công cụ Entity Data Model Wizard. Bạn có thể thay đổi data model và cập nhật lại vào database. Đây là cách tiếp cận phổ biến vì cách thực hiện đơn giản, nhanh chóng

Model First

Hướng tiếp cận này được bổ sung từ phiên bản EF 4 trong Visual 2010. Bạn có thể tạo một data model rỗng bằng công cụ Entity Data Model Designer, khi đó object layer cũng tự động được sinh ra. Sau khi đã hoàn thành việc thiết kế, bạn có thể sử dụng chức năng Generate Database from Model để tạo ra các mã DDL (data definition language) dựa trên mã SSDL (Store Schema Definition Language). Các mã DDL này sẽ được thực thi và lưu thành tập tin .sql

Code First

Với phiên bản EF 4 bạn cần phải cài thêm thư viện EF Feature CTP (Community Technology Preview) để sử dụng. Tuy nhiên tính năng này đã được tích hợp vào trong phiên bản EF 4.1 và với phiên bản VS 2010 hiện tại thì bạn cần phải download để cài đặt thủ công. Hướng tiếp cận này bỏ qua phần Model (.edmx), bạn có thể thiết kế các class tương ứng với các table của database mà bạn cần làm việc hoặc muốn tạo ra. Với hướng tiếp cận này, bạn sẽ sử dụng class DbContext thay vì ObjectContext để thao tác với database. Việc sử dụng Code First đòi hỏi bạn phải thực hiện các công việc một cách thủ công nhưng bù lại nó linh hoạt và được sử dụng rất phổ biến.

Sử dụng các Database first

01Tạo mới Project với kiểu Windows Form Application.
Lưu Project với tên bất kỳ (trong ví dụ này lấy tên DemoEF1)

02Nhấn Add New Item (Ctrl+Shift+A) trên thanh công cụ và chọn mục ADO.NET Entity Data Model trong hộp thoại hiện ra. Đặt tên mục ssẽ thêm vào là  BookDbModel với phần mở rộng mặc định là .edmx. Nhấn Add để tiếp tục.

Add New ADO.NET Entity Data ModelAdd New ADO.NET Entity Data Model

03Cửa sổ Entity Data Model Wizard hiện ra. Bước này để xác định bạn sẽ tạo model từ database có sẵn hoặc một model rỗng. Bạn để lựa chọn mặc định là Generate from database và nhấn Next.

Entity Data Model WizardEntity Data Model Wizard

04Bước này bạn cần chọn database nào sẽ sử dụng. Chuỗi kết nối sẽ tự động được sinh trong phần Entity connection string. Với tùy chọn Save entity connection settings in App.Config, chuỗi kết nối này sẽ tự động được thêm vào tập tin App.Config, nhờ đó bạn không cần nhớ chuỗi kết nối mà chỉ cần nhớ tên của kết nối là BookDbEntities. Trong trường hợp bạn chưa có sẵn kết nối với database nào, hãy nhấn nút New Connection… Các kết nối mà bạn đã tạo sẽ hiện ra trong cửa sổ Server Explorer. Nhấn Next.

05Lựa chọn các table, view và stored procedure bạn muốn sử dụng. Nhấn Finish.

Entity Data Model WizardEntity Data Model Wizard

06Sau khi nhấn Finish, tập tin BookDbModel.edmx sẽ được thêm vào Solution Explorer. Đây là tập tin có dạng .xml và được mở với trình mặc định ADO.NET Entity Data Model Designer với giao diện trực quan như hình dưới. Nếu muốn coi nội dung của tập tin này dưới dạng văn bản .xml, bạn nhấn chuột phải vào tập tin trong Solution Explorer -> Open With… và chọn XML Editor. Bạn có thể coi các thông tin đầy đủ của model trong cửa sổ Model Browser và Mapping Details.
Ngoài tập tin .edmx trên, một tập tin khác cũng được tự động tạo ra là BookDbModel.Designer.cs. Tập tin này chứa code C# được sinh ra cho các class bạn sẽ sử dụng trực tiếp khi lập trình. Các class này được gọi là Object Layer (là phần Object Services trong kiến trúc của Entity Framework).
Khảo sát tập tin này, bạn sẽ thấy nó bao gồm các class là: BookDbEntities, Book, Category . Trong đó, class  BookDbEntities chính là class thừa kế từ ObjectContext mà bạn cần sử dụng để tạo kết nối và thao tác với database.

Mapping Model DetailMapping Model Detail

Coding

Sau đây là mã nguồn chính của Project:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;

namespace DemoEF1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            //Khởi tạo các thành phần của form
            InitializeComponent();

            //Khởi tạo các thành phần tích hợp khác trên form nếu có

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            cbbCategory.DataSource = GetAllCategories();
            cbbCategory.DisplayMember = "CategoryName";
            cbbCategory.ValueMember = "Id";

            //Khởi tạo các thành phần bổ sung của form
            InitializeListView();
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            //dgvBook.DataSource = GetBooksByCategory(int.Parse(cbbCategory.SelectedValue.ToString()));
            BindToListView(GetBooksByCategory(int.Parse(cbbCategory.SelectedValue.ToString())));
        }

        private void InitializeListView()
        {
            this.lvBooks.FullRowSelect = true;
            this.lvBooks.GridLines = true;
            this.lvBooks.View = View.Details;

            this.lvBooks.Columns.Add("Id", 26);
            this.lvBooks.Columns.Add("Title", 150);
            this.lvBooks.Columns.Add("Author", 140);
            this.lvBooks.Columns.Add("Category", 100);
        }

        private void BindToListView(List<Book> books)
        {
            this.lvBooks.Items.Clear();
            foreach (Book b in books)
            {
                ListViewItem lvi = new ListViewItem(b.Id.ToString());
                lvi.SubItems.Add(b.Title);
                lvi.SubItems.Add(b.Author);
                lvi.SubItems.Add(b.Category.CategoryName);
                lvBooks.Items.Add(lvi);
            }
        }

        // Select - dùng Linq to Entities query
        private List<Book> GetBooksByCategory(int categoryId)
        {
            using (BookDbEntities context = new BookDbEntities())
            {
                var books = from b in context.Books.Include("Category")
                            where b.Category.Id == categoryId
                            select b;
                return books.ToList();
            }
        }

        // Select - dùng Entity SQL query
        private List<Book> GetBooksByCategoryUsingEntitySQL(int categoryId)
        {
            using (BookDbEntities context = new BookDbEntities())
            {
                String sqlQuery = @"SELECT VALUE b FROM BookDbEntities.Books as b WHERE b.Category.Id=@id";
                ObjectQuery<Book> booksQuery = context.CreateQuery<Book>(sqlQuery,new ObjectParameter("Id",categoryId)).Include("Category");
                return booksQuery.ToList();
            }
        }

        private List<Category> GetAllCategories()
        {
            using (BookDbEntities context = new BookDbEntities())
            {
                context.ContextOptions.LazyLoadingEnabled = false;
                var categories = context.Categories;
                return categories.ToList();
            }
        }

        private Book GetBookById(int id)
        {
            using (BookDbEntities context = new BookDbEntities())
            {
                Book book = context.Books.Where(b => b.Id == id).FirstOrDefault();
                return book;
            }
        }

        private Category GetCategoryById(int id)
        {
            using (BookDbEntities context = new BookDbEntities())
            {
                Category category = context.Categories.Where(b => b.Id == id).FirstOrDefault();
                return category;
            }
        }

        private void cbbCategory_SelectedIndexChanged(object sender, EventArgs e)
        {
            int id;
            if (int.TryParse(cbbCategory.SelectedValue.ToString(),out id))
                BindToListView(GetBooksByCategory(int.Parse(cbbCategory.SelectedValue.ToString())));
        }

        private void lvBooks_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvBooks.SelectedItems.Count > 0)
            {
                Book book = GetBookById(int.Parse(lvBooks.SelectedItems[0].SubItems[0].Text));
                txtName.Text = book.Title;
                txtAuthor.Text = book.Author;
            }
        }

        //Thêm mới
        private void btnAdd_Click(object sender, EventArgs e)
        {
            using (BookDbEntities context = new BookDbEntities())
            {
                Book book = new Book();
                book.Title = txtName.Text;
                book.Author = txtAuthor.Text;
                book.CategoryId = int.Parse(cbbCategory.SelectedValue.ToString());

                context.Books.AddObject(book);
                context.SaveChanges();
            }
            BindToListView(GetBooksByCategory(int.Parse(cbbCategory.SelectedValue.ToString())));
        }

        //Xóa
        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (lvBooks.SelectedItems.Count < 0)
                return;
            using (BookDbEntities context = new BookDbEntities())
            {
                Book book = GetBookById(int.Parse(lvBooks.SelectedItems[0].SubItems[0].Text));

                context.Books.Attach(book);
                context.Books.DeleteObject(book);
                context.SaveChanges();
            }
            BindToListView(GetBooksByCategory(int.Parse(cbbCategory.SelectedValue.ToString()))); 
        }

        //Cập nhật
        private void btnUpdate_Click(object sender, EventArgs e)
        {
            if (lvBooks.SelectedItems.Count < 0) return;
            using (BookDbEntities context = new BookDbEntities())
            {
                Book book = GetBookById(int.Parse(lvBooks.SelectedItems[0].SubItems[0].Text));

                book.Title = txtName.Text;
                book.Author = txtAuthor.Text;
                context.Books.Attach(book);
                context.ObjectStateManager.ChangeObjectState(book, EntityState.Modified);
                context.SaveChanges();
            }
            BindToListView(GetBooksByCategory(int.Parse(cbbCategory.SelectedValue.ToString()))); 
        }
    }
}
Demo Entity Framework ProjectDemo Entity Framework Project

 

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s

%d bloggers like this: