Sử dụng nhiều DbContext trong EF Code First

Trong thực tế, đối với các ứng dụng lớn, bạn sẽ cần phải dùng đến DbContextcho những mục đích nghiệp vụ khác nhau, hoặc nói cách khác, nếu bạn đã biết về kiểu phát triển theo hướng Domain Driven Design (tham khảo về Domain Design) thì từng domain sẽ sử dụng DBContext thích hợp, gọi chung là Bounded Context, khi đó, trong ứng dụng của bạn lúc này sẽ có nhiều Bounded Context. Trong bài viết này, mình sẽ trình bày sơ qua về cách sử dụng Bounded Context này, để tìm hiểu thêm, các bạn có thể tham khảo bài viết của Julie Lerman trên MSDN. Phiên bản hiện tại của EF là 5.0, và chỉ hỗ trợ 1 DbContext cho 1 CSDL.

Các domain class sử dụng trong ví dụ minh họa cho bài viết này:

</pre>
namespace DomainClasses
{
 public class Blog
 {
 public int BlogId { get; set; }
 [Required]
 public string Name { get; set; }

 public virtual List<Post> Posts { get; set; }
 }

 public class Post
 {
 public int PostId { get; set; }
 [Required]
 public string Title { get; set; }
 [Required]
 public string Content { get; set; }
 public string Note { get; set; }
 public string NewNote { get; set; }

 public int BlogId { get; set; }
 public virtual Blog Blog { get; set; }
 }

 public class User
 {
 public int UserId { get; set; }
 public DateTime SignInDate { get; set; }
 }

 #region Location

 public class District
 {
 public int DistrictId { get; set; }
 public string Name { get; set; }
 }

 public class City
 {
 public int CityId { get; set; }
 public string Name { get; set; }

 }

 public class Country
 {
 public int CountryId { get; set; }
 public int Name { get; set; }
 }

 #endregion
}
<pre>

Trong này, mình đơn giản hóa bằng cách giảm thiểu về phần relationship giữa các domain class và tập trung vào cách hoạt động khi sử dụng Bounded Context.

Ban đầu, mình sẽ tạo ra một DbContext chung sử dụng cho việc tạo và migration toàn bộ CSDL đặt tên là DemoDatabseModel.cs:

</pre>
public class DemoDatabaseModel : DbContext
 {
 public DbSet<Blog> Blogs { get; set; }
 public DbSet<Post> Posts { get; set; }
 public DbSet<User> Users { get; set; }
 public DbSet<District> Districts { get; set; }
 public DbSet<City> Cities { get; set; }
 public DbSet<Country> Countries { get; set; }
 }
<pre>

Sau đó, đối với từng domain, mình sẽ tạo ra các Bounded Context riêng. Nhưng trước hết mình sẽ tạo ra 1 Context cơ sở, đặt tên là BaseContext, và các Bounded Context sẽ thực hiện việc kế thừa Context cơ sở này.

</pre>
public class BaseContext<TContext> : DbContext where TContext : DbContext
 {
 static BaseContext()
 {
 Database.SetInitializer<TContext>(null);
 }

 protected BaseContext() : base("BoundedContextDemo") { }
 }
<pre>

Trong ví dụ minh họa, mình sẽ tạo ra 2 Bounded Context là BlogsBoundedContext và LocationsBoundedContext như sau:

</pre>
namespace BlogsBoundedContext
{
 public class BlogContext : BaseContext<BlogContext>
 {
 public DbSet<Blog> Blogs { get; set; }
 public DbSet<Post> Posts { get; set; }
 public DbSet<User> Users { get; set; }
 }
}
namespace LocationsBoundedContext
{
 public class LocationContext : BaseContext<LocationContext>
 {
 public DbSet<Blog> Blogs { get; set; }
 public DbSet<Post> Posts { get; set; }
 public DbSet<User> Users { get; set; }
 }
}
<pre>/code]</pre>
Như vậy, phần thiết kế các Bouned Context theo Domain Driven Design ban đầu đã xong. Bây giờ chúng ta tạo ra CSDL và chèn dữ liệu mẫu vào trước khi kiểm tra việc hoạt động của các Bounded Context này.

Để đơn giản, ở đây chúng ta sẽ tạo ra 1 console application., trong tập tin Program.cs, chúng ta sẽ viết mã nguồn như sau để tạo CSDL:

</pre>
class Program
 {
 static void Main(string[] args)
 {
 CreateDatabse();
 }

 public static void CreateDatabse()
 {
 var context = new DemoDatabaseModel();
 context.Database.Initialize(true);
 }
 }
<pre>

Các bạn thực hiện việc build solution và kiểm tra xem CSDL đã được tạo ra hay chưa.

boundedcontext_efcodefirst_1

Vậy là việc tạo CSDL ban đầu đã xong, bây giờ bạn hãy thêm các record mẫu cho các bảng này. Sau đó chúng ta sẽ kiểm tra xem rằng Bounded Context có truy xuất đến cùng database hay không bằng cách viết hàm sau vào tập tin Program.cs:

</pre>
public static bool CanRetrieveInfoFromBlogContext()
 {
 var context = new BlogContext();
 Debug.WriteLine(context.Database.Connection.ConnectionString);
 return context.Blogs.Any();
 }
<pre>

Sau đó gọi hàm này trong hàm Main và xem kết quả

boundedcontext_efcodefirst_2

Oh oh, lỗi rồi. Lý do là trong mã nguồn của BaseContext class, chúng ta khai báo không đúng CSDL cần truy xuất, đó là “BoundedContextDemo”, trong khi đó CSDL chúng ta đang truy xuất hiện tại là “DemoDatabaseInitialization.DemoDatabaseModel” mặc định do Code First tạo ra. Việc đơn giản ở đây là chúng ta chỉ việc khai báo lại tên CSDL trong BaseContext class và build lại solution.

</pre>
protected BaseContext() : base("DemoDatabaseInitialization.DemoDatabaseModel") { }
<pre>

Kết quả là

boundedcontext_efcodefirst_3

Bây giờ chúng ta hãy thử kiểm tra xem Bounded Context có lấy đượct thông tin từ CSDL ra hay không bằng cách viết thêm hàm sau:

</pre>
public static Post GetTheFirstRecordFromPostTable()
 {
 Post post = new Post();
 var context = new BlogContext();
 post = context.Posts.FirstOrDefault();
 return post;
 }
<pre>

Sau đó gọi hàm này trong hàm Main, build solution và xem kết quả


Console.WriteLine(GetTheFirstRecordFromPostTable().Title;

boundedcontext_efcodefirst_4

Hurray, đã lấy được. Như vậy, đến đây bạn có thể hiểu được phần nào về Bounded Context là gì, mục đích sử dụng của nó trong Domain Driven Design là như thế nào. Chúc các bạn tạo ra được những ứng dụng tốt với EF Code First.

Link download source code minh họa trong bài: Download.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s