เริ่มต้นเรียนรู้ Entity Framwork Code First

วันนี้เราจะมาทำความรู้จักและใช้งาน Entity Framework กัน 

Entity Framework คืออะไร ?

Entity Framework เป็นเทคโนโลยีที่ทำให้เราให้สามารถเขียนคำสั่งในการ query ข้อมูล database ด้วยภาษา C# หรือ VB เราแทบไม่ต้องเขียน SQL statement เพื่อดึงข้อมูลจาก database เลยก็ได้ แต่ Entity Framework ก็เปิดโอกาสให้เราสามารถเขียน SQL statement ได้เหมือนกัน แต่การเขียน SQL statement รวมเข้าไปในคำสั่ง C#  จะมีข้อจำกัดคือ

Entity Framework หากพูดในเชิง technical ถือว่าเป็น ORM (Object Relational Mapping) framework สำหรับ .NET Application (Windows Form, ASP.NET, ASP.NET MVC,WPF, WCF, Silverlight , etc) ORM เป็นตัวกลางในการติดต่อกันระหว่าง database และภาษา object oriented (C#, VB)

เมื่อรู้แล้วว่า Entity Framework คืออะไร เรามาเริ่มสร้าง project เพื่อใช้งาน Entity Framework กันเลย

1. เปิด Visual Studio 2010 สร้าง Project ใหม่ ไปที่ File > New Project...> Visual C# > Windows > Console Application ตั้งชื่อ project ว่า CodeFirstSample กดปุ่ม OK เพื่อสร้าง project

2. ติดตั้ง Entiry Framework 4.2 โดยเริ่มจากคลิกเลือกชื่อ project CodeFirstSample ที่ Solution Explorer ดังภาพต่อไปนี้

ไปที่ Tool > Library Pagekage Manage > Pagekage Manager Console เปิด Pagekage Manager Console ที่อยู่ด้านล่างของหน้าจอขึ้นมา

ให้พิมพ์คำสั่ง ต่อไปนี้ต่อจาก PM>

Install-Package EntityFramework

แล้วตามด้วยปุ่ม Enter เพื่อเรียกใช้คำสั่งให้ทำการติดตั้ง Entity Framework version ล่าสุด (4.2 ณ เวลาที่เขียนบทความนี้)
ผลลัพธ์ที่แสดงหลังจากติดตั้งเรียบร้อยแล้ว

PM> Install-Package EntityFramework
You are downloading EntityFramework from Microsoft, the license agreement to which is available at http://go.microsoft.com/fwlink/?LinkID=231818. Check the package for additional dependencies, which may come with their own license agreement(s). Your use of the package and dependencies constitutes your acceptance of their license agreements. If you do not accept the license agreement(s), then delete the relevant components from your device.
Successfully installed 'EntityFramework 4.2.0.0'.
Successfully added 'EntityFramework 4.2.0.0' to CodeFirstSample.

PM>

สามารถศึกษาการใช้งาน Pagekage Manager Console ได้จาก NuGet นำ .NET class library ต่างๆ มาใช้ใน project ของเราได้อย่างง่ายดาย

3. สร้าง App.Config ไฟล์เพื่อกำหนดค่า connection string ในการเชื่อมต่อกับ database

ไปที่ Solution Explorer คลิกเลือก CodeFirstSample > คลิกขวา เลือก Add > New Item..
เลือก Application Configuration File ตามขั้นตอนที่มีหมายเลขกำกับดังรูปภาพต่อไปนี้

เพิ่มคำสั่งต่อไปนี้เข้าไปใน App.config ภายใน configuration element

 <connectionStrings>
            <add name="MyProductContext"
              providerName="System.Data.SqlClient"
              connectionString="Server=.\SQLEXPRESS;Database=Products;Trusted_Connection=true;"/>
</connectionStrings>

save App.cofig file ดังนั้นคำสั่งทั้งหมดใน App.config ที่ได้จะมีหน้าตาดังนี้

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <connectionStrings>
        <add name="MyProductContext"
          providerName="System.Data.SqlClient"
          connectionString="Server=.\SQLEXPRESS;Database=Products;Trusted_Connection=true;"/>
    </connectionStrings>
</configuration>

4. สร้าง class ที่มีโครงสร้างเหมือนกับ table ที่เราจะออกแบบเพื่อเก็บข้อมูล (Model Class)

สร้าง class ใหม่ขึ้นมาให้ชื่อว่า Category และ Product

ใน Category.cs มีโครงสร้างของ class เป็นคำสั่งดังนี้

using System.Collections.Generic;

namespace CodeFirstSample
{
    public class Category
    {
        public string CategoryId { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Product> Products { get; set; }

    }
}

ใน Product.cs มีโครงสร้างของ class เป็นคำสั่งดังนี้

namespace CodeFirstSample
{
    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public string CategoryId { get; set; }
        public virtual Category Category { get; set; }
    }
}

5.สร้าง DbContext Class เพื่อติดต่อกับ database

class เพื่อใช้ติดต่อกับ database ต้องสืบทอดจาก System.Data.Entity.DbContext  และมีสมาชิก DbSet<TEntity> ซึ่ง TEntity คือ class ที่สร้างขึ้นมาเป็นตัวแทน table ใน database ในตัวอย่างนี้หมายถึง Category และ Product

สร้าง class ใหม่ชื่อว่า ProductContext

ใน ProductContext.cs มีโครงสร้างของ class เป็นคำสั่งดังนี้

using System.Data.Entity;

namespace CodeFirstSample
{
    public class ProductContext : DbContext
    {
        public DbSet<Category> Categories { get; set; }
        public DbSet<Product> Products { get; set; }
        public DbSet<Supplier> Suppliers { get; set; }
    }
}

6. ทดลองเขียนคำสั่งเก็บข้อมูลลง database
เปิด Program.cs

เพิ่มคำสั่งเข้าไปใน Main method เพื่อเก็บข้อมูลลง database

using System;

namespace CodeFirstSample
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var db = new ProductContext())//สร้าง DbContext
            {
                // สร้าง Category ใหม่
                var food = new Category { CategoryId = "FOOD", Name = "Foods" };
                //เพิ่ม Category เข้าไปใน DbContext
                db.Categories.Add(food);
                //บันทึก Category เข้า database
                int recordsAffected = db.SaveChanges();
                //แสดงผลลัพธ์การทำงานที่หน้าจอ
                Console.WriteLine("Saved {0} entities to the database, press any key to exit.", recordsAffected);
                Console.ReadKey();
            } 
        }


    }

}

กด F5 เพื่อ run program

ผลลัพธ์ที่แสดงหน้าจอ (command prompt)

Saved 1 entities to the database, press any key to exit.

ข้อมูลถูกเก็บที่ไหน ???

จริงๆ แล้ว DbContext จะสร้าง database ขึ้นมาโดยอัตโนมัติบน localhost\SQLEXPRESS (database server ของ MS SQL Server Express Edition)
โดยปกติ database จะถูกตั้งชื่อตามชื่อเต็มของ DbContext ในที่นี้คือ CodeFirstSample.ProductContext

นอกจากนี้ DbContext จะทำการสร้าง table ขึ้นใน database จาก DbSet properties ที่ถูกสร้างไว้ รูปแบบของ table, field ต่างๆ , primary key จะถูกสร้างตามรูปแบบที่ DbContext กำหนดไว้ในลักษณ Convention เช่น ProductContext มี DbSet เป็น Product และ Category Class ดังนั้นใน database CodeFirstSample.ProductContext จะมี table Product และ Category ใน Product และ Category class มี property ที่ชื่อว่า ProductId และ CategoryId DbContext จะเข้าใจเลยว่าทั้งสอง Filed นี้เป็น primary key เพราะมี pattern 
ชื่อ class + Id
 

7.ทดลองเขียนคำสั่งเพิ่ม อ่านและเก็บข้อมูลลง database

แก้ไข Main method เพื่ออ่านและเก็บข้อมูลลง database ให้อยู่ในรูปแบบคำสั่งดังต่อไปนี้

using System;
using System.Linq;

namespace CodeFirstSample
{
    class Program
    {

        static void Main(string[] args)
        {
            using (var db = new ProductContext())
            {
                // ค้นหา Food category
                var food = db.Categories.Find("FOOD");

                //ถ้าไม่เจอ Food มีค่าว่าง, สร้างขึ้นมาใหม่แล้วเพิ่มเข้าไปใน ProductContext
                if (food == null)
                {
                    food = new Category { CategoryId = "FOOD", Name = "Foods" };
                    db.Categories.Add(food);
                }

                //สร้าง product ใหม่ 
                Console.Write("Please enter a name for a new food: ");
                var productName = Console.ReadLine();

                //ใน product ที่สร้างมีการกำหนดค่า Category เข้าไปด้วย
                var product = new Product { Name = productName, Category = food };
                //เพิ่ม product เข้าไปใน ProductContext
                db.Products.Add(product);

                //บันทึกข้อมูลลง database
                int recordsAffected = db.SaveChanges();
                Console.WriteLine("Saved {0} entities to the database.", recordsAffected);

                //ดึง product ทั้งหมดที่มี category เป็น FOOD ออกจาก database โดย LINQ query syntax
                var allFoods = from p in db.Products
                               where p.CategoryId == "FOOD"
                               orderby p.Name
                               select p;

               // เราสามารถเขียนคำสั่งได้อีกรูปแบบที่เรียกว่า method syntax จะเขียนแบบใดขึ้นอยู่กับความถนัด
               // var allFoods = db.Products.Where(p => p.CategoryId == "FOOD");

                //แสดงชื่ของ product ทั้งหมดออกสู่หน้าจอ Command Prompt 
                Console.WriteLine("All foods in database:");
                foreach (var item in allFoods)
                {
                    Console.WriteLine(" - {0}", item.Name);
                }

                Console.WriteLine("Press any key to exit.");
                Console.ReadKey();
            }
        }
    }

}

8.กำหนดค่าเริ่มต้นในขั้นตอนการสร้าง database
ต่อไปเราจะเพิ่ม Model Class Supplier เข้ามา เท่ากับว่าเราได้ทำการเปลี่ยนแปลงโครงสร้างของ database ด้วยการสร้าง table Suppliers ดังนั้น DbContext มีโครงสร้าง property ที่ไม่ตรงกับ database DbContext มี 3 property แต่ database ได้ถูกสร้างขึ้นมาแล้วก่อนหน้านี้และมีเพียง 2 table ด้วยเหตุนี้หากเปิดโปรแกรมก็จะทำให้เกิด run time error วิธีการแก้อย่างง่ายคือให้ DbContext ทำการ drop และสร้าง dabase ใหม่ทุกครั้งที่เรามีการแก้ไข DbContext class ในที่นี้คือ ProductContext
ทำได้โดยเพิ่มคำสั่งต่อไปนี้เข้าบรรทัดบนสุดภายใน Main method

 

 Database.SetInitializer<ProductContext>(new DropCreateDatabaseIfModelChanges<ProductContext>());

9.กำหนดค่าให้กับ Model Class เพื่อทำการ mapping กับ database ได้ถูกต้อง
เพิ่ม Suppliers Class และเพิ่ม property Suppliers เข้าไปใน ProductContext

Suppliers.cs

namespace CodeFirstSample
{
    public class Supplier
    {
        public string SupplierCode { get; set; }
        public string Name { get; set; }
    }
}

ProductContext.cs

using System.Data.Entity;

namespace CodeFirstSample
{
    public class ProductContext : DbContext
    {
        public DbSet<Category> Categories { get; set; }
        public DbSet<Product> Products { get; set; }
        public DbSet<Supplier> Suppliers { get; set; } 
    }
}



Data Annotations & Fluent API

Supplier class มี property SupplierCode ที่เป็น primary key แต่ เนื่องจากไม่ได้ถูกกำหนดชื่อให้เป็นไปตามที่ DbContext เข้าใจได้อัตโนมัติเพื่อนำไปสร้างเป็น primary key field ใน table Suppliers ดังนั้น เราจึงต้องทำการกำหนดค่าเองเพื่อบอกให้ DbContext ทราบว่า property นี้คือ primary key เราสามารถทำได้สองวิธีคือ Data Annotations และ Fluent API
เริ่มด้วยการกำหนด primary key ผ่าน Data Annotations
Data Annotations Attribute ที่นำไปวางบน property ได้เลย
คำสั่งที่ได้จะเป็นดังนี้
 

using System.ComponentModel.DataAnnotations;

namespace CodeFirstSample
{
    public class Supplier
    {
        [Key]
        public string SupplierCode { get; set; }
        public string Name { get; set; }
    }
}

Data Annotations ที่ Entity Framework มีมาให้เพื่อใช้กับ model class
 

กำหนด primary key ผ่าน Fluent API
วิธีการนี้เราจะเขียนคำสั่ง override OnModelCreating method ของ DbContext (ProductContext) เพิ่มคำสั่งในรูปแบบ Fluent API เข้าไปใน OnModelCreating method
รูปแบบคำสั่งจะเป็นดังนี้

 

using System.Data.Entity;

namespace CodeFirstSample
{
    public class ProductContext : DbContext
    {
        public DbSet<Category> Categories { get; set; }
        public DbSet<Product> Products { get; set; }
        public DbSet<Supplier> Suppliers { get; set; }

        //กำหนด primary key ผ่าน Fluent API
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Supplier>()
                .HasKey(s => s.SupplierCode);
        } 

    }
}

ในทางปฏิบัติแนะนำให้กำหนด Model Class ด้วย Data Annotations ก่อน หากไม่สามารถกำหนดได้ตามต้องการจึงค่อยใช้ Fluent API

กดปุ่ม F5 เพื่อทดลอง run program


โครงสร้างของ database เมื่อเปิดดูด้วย SQL Server Management Studio

download source code ตัวอย่างในบทความนี้ (VS 2010 project file)

ลองนำไปใช้กันดูนะครับ

ตัวอย่างและเนื้อหาในบทความนี้ดัดแปลงมาจาก
credit http://blogs.msdn.com/b/adonet/archive/2011/09/28/ef-4-2-code-first-walkthrough.aspx

ความเห็น

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Friends
jirawat.in.th clipdonjai.com janawat.wordpress.com csharp89.blogspot.com 108blog.net

HTML5 Powered with Multimedia