Thiết kế Entity Data Model – Part 3: Code First

Bài này giới thiệu cách sử dụng EF 4.1 để thiết kế Entity Data Model theo hướng Code First.

Sử dụng Code First, bạn phải làm thủ công toàn bộ việc định nghĩa các class của object layer. Nhờ đó bạn sẽ hiểu sâu hơn cách hoạt động và cấu trúc của các class này.

ADO.NET Entity Framework 4.2

Phiên bản EF 4.1 cung cấp hai tính năng mới:

  • The DbContext API is a simplified abstraction over ObjectContext and a number of other types that were included in previous releases of the ADO.NET Entity Framework. The DbContext API surface is optimized for common tasks and coding patterns.
  • Code First is a new development pattern for the ADO.NET Entity Framework and provides an alternative to the existing Database First and Model First patterns. Code First is focused around defining your model using C#/Visual Basic .NET classes, these classes can then be mapped to an existing database or be used to generate a database schema. Additional configuration can be supplied using Data Annotations or via a fluent API.

Phiên bản 4.2 vừa được phát hành đầu tháng 11/2011 và  sửa một số lỗi của phiên bản EF 4.1. Để cài đặt EF 4.2, bạn cần dùng đến công cụ Package Manager Console trong Visual Studio. Công cụ được cung cấp trong menu Tools> Library Package Manager>Package Manager Console.

Khi cửa sổ này được mở ra, tại dấu nhắc dòng lệnh PM>, hãy gõ vào “Install-Package EntityFramework”, hãy chờ một lúc để chương trình download và cài đặt EF 4.2.

Nếu cần gỡ bỏ, bạn có thể gõ lệnh “Uninstall-Package EntityFramework”.

Tạo các entity class

Để sử dụng Code First trong Entity Framework, bạn cần phải thêm tham chiếu đến các assembly cần thiết vào dự án:

  • EntityFramework
  • System.ComponentModel.DataAnnotations
  • System.Data.Entity

Với phiên bản EF 4.1, bạn có thể thêm các tham chiếu thủ công. Tuy nhiên với EF 4.2, bạn có thể làm điều này bằng cách cài đặt package EntityFramework.Preview. Bạn thực hiện điều này bằng cách làm theo các bước sau:

–          Tạo một dự án với tên EntityFrameworkDemo.

–          Vào menu Project>Add Library Package Reference.

–          Trong cửa sổ hiện ra, qua thẻ Online và gõ vào textbox tìm kiếm tên của package là “EntityFramework.Preview”.

–          Sau khi tìm được, nhấn Install để tiến hành cài đặt.

Sau đó, bạn có thể tạo các class để thực hiện thao tác với database. Trong ví dụ này tôi sẽ tạo các class cho database như sau:

Các class của object layer, bao gồm một context và các entity được định nghĩa trong C# như sau:

public class CompanyContext : DbContext

{

    public DbSet<Author> Authors { get; set; }

    public DbSet<Article> Articles { get; set; }

    public DbSet<Payroll> Payrolls { get; set; }

}

public class Author

{

    public int AuthorId { get; set; }

    public string Name { get; set; }

    public ICollection<Article> Articles { get; set; }

}

public class Article

{

    public int ArticleId { get; set; }

    public string Name { get; set; }

    public int AuthorId { get; set; }

    public Author Author { get; set; }

}

public class Payroll

{

    public int PayrollId { get; set; }

    public int AuthorId { get; set; }

    public int Salary { get; set; }

    public Author Author { get; set; }

}

Bổ sung thông tin cho các entity class với Data Annotation

Các field của một table cần phải được xác định các thông tin như kiểu dữ liệu, khóa chính, … Tôi làm điều này bằng cách dùng các attribute trong System.ComponentModel.DataAnnotations.

Ví dụ trong class Author, tôi xác định AuthorId là khóa chính bằng attribute [Key], và xác định số kí tự tối đa cho Name là 100 bằng attribute [StringLength].

public class Author

{

    [Key]

    public int AuthorId { get; set; }

    [StringLength(100)]

    public string Name { get; set; }

    public ICollection<Article> Articles { get; set; }

}

Danh sách các annotation mà EF hỗ trợ bao gồm:

- KeyAttribute

- StringLengthAttribute

- MaxLengthAttribute

- ConcurrencyCheckAttribute

- RequiredAttribute

- TimestampAttribute

- ComplexTypeAttribute

- ColumnAttribute

- Placed on a property to specify the column name, ordinal & data type

- TableAttribute

- Placed on a class to specify the table name and schema

- InversePropertyAttribute

- Placed on a navigation property to specify the property that represents the other end of a relationship

- ForeignKeyAttribute

- Placed on a navigation property to specify the property that represents the foreign key of the relationship

- DatabaseGeneratedAttribute

- Placed on a property to specify how the database generates a value for the property (Identity, Computed or None)

- NotMappedAttribute

- Placed on a property or class to exclude it from the database

Bạn có thể tham khảo hướng dẫn về các annotation này tại Data Annotations in the Entity Framework and Code First.

Kiểm tra kết quả

Để kiểm tra các class đã tạo trên, tôi thực hiện chèn hai dòng dữ liệu vào hai table Authors và Articles. Các table này tương ứng là hai property Authors và Articles của đối tượng CompanyContext. Sau khi đã thực hiện chèn dữ liệu vào, tôi sẽ thử sử dụng một navigation property là Article.Author để xem nó có trả về đúng kết quả không.

static void Main(string[] args)

{

    using (var db = new CompanyContext())

    {

        var author = new Author { Name = "Stanford day lap trinh" };

        var article = new Article { Name = "Code First and Entity Framework 4.2"};

        article.AuthorId = author.AuthorId;

        db.Authors.Add(author);

        db.Articles.Add(article);

        db.SaveChanges();

        var au = article.Author;

        Console.WriteLine("Author: "+ au.AuthorId + " - " + au.Name);

    }

    Console.ReadKey();

}

Kết quả

Author: 1 - Stanford day lap trinh

Như bạn thấy tôi hoàn toàn không gán giá trị cho property article.Author, nhưng property này article hoàn toàn chứa tham chiếu đến đối tượng author mà tôi đã chèn vào database, và do đó, in ra được thông tin của author.

Mở Sql Server lên, bạn có thể thấy một database mới tự động được tạo với tên EntityFrameworkDemo.CompanyContext, đây chính là tên đầy đủ của class context mà tôi tạo trong phần trên.

Xác định database sẽ kết nối với connection string

Class DbContext cho phép truyền một  chuỗi kết nối vào constructor. Vì vậy nếu như đã có sẵn một database hoặc muốn đặt tên cho database sẽ được tạo ra, bạn có thể xác định bằng cách truyền chuỗi kết nối cho DbContext. Ví dụ tôi muốn database sẽ được tạo ra phải tên là “Y2Company”, tôi thực hiện bằng cách thêm một chuỗi kết nối với tên “MyCompany” vào tập tin App.Config.

<connectionStrings>

  <add name="MyCompany"

    providerName="System.Data.SqlClient"

    connectionString="Server=.\SQLEXPRESS;Database=Y2Company;Trusted_Connection=true;"/>

<!--...-->

</connectionStrings>

Thêm constructor sử dụng tham số kiểu chuỗi cho class CompanyContext:

public class CompanyContext : DbContext

{

    public DbSet<Author> Authors { get; set; }

    public DbSet<Article> Articles { get; set; }

    public DbSet<Payroll> Payrolls { get; set; }

    public CompanyContext()

    { }

    public CompanyContext(string connectionString)

        :base(connectionString)

    { }

}

Và sửa lại một chút trong phương thức Main(), chú ý phần khởi tạo đối tượng CompanyContext:

var db = new CompanyContext("name=MyCompany");

Tags: