Entity Data Model (EDM), như bạn đã học trong bài “Kiến trúc Entity Framework“, là thành phần lưu trữ thông tin ánh xạ (mapping) giữa các class và cơ sở dữ liệu. EDM đóng vai trò cầu nối giữa các lớp model và cơ sở dữ liệu. Toàn bộ những kiến thức các bạn học trong chương này đều tập trung vào các kỹ thuật xây dựng EDM sử dụng tiếp cận code-first.
Trong bài thực hành này chúng ta sẽ cùng vận dụng những kiến thức và kỹ năng đã học để xây dựng một EDM hoàn chỉnh theo tiếp cận code-first. EDM xây dựng ở bài học này sẽ ở mức độ hoàn thiện để có thể sử dụng trong các project khác. Bạn cũng sẽ sử dụng EDM này trong chương tiếp theo khi bạn học cách truy vấn và lưu trữ dữ liệu.
[signinlocker id=”16252″]
Tạo solution, Models và DataAccess
Bước 1. Tạo một blank solution và thêm hai project đều thuộc loại Class Library (.NET Framework) đặt tên lần lượt là Models và DataAccess.
Bước 2. Cho DataAccess tham chiếu sang Models.
Bước 3. Cài đặt thư viện Entity Framework cho DataAccess.
Bạn thu được kết quả như sau:
Khi phát triển ứng dụng, đặc biệt là ứng dụng quản lý (Line-of-Business, LOB) với Entity Framework, người ta thường xây dựng hai project riêng biệt thuộc loại Class Library. Tên gọi thông dụng là (1) Models và (2) DataAccess.
Project thứ nhất (Models) chỉ chứa các domain class, gọi chung là các model. Đây là các POCO (Plain Old C# Object) và sẽ được ánh xạ thành các bảng tương ứng của cơ sở dữ liệu. Project này luôn được xây dựng đầu tiên trong solution. Project này không tham chiếu đến bất kỳ thư viện hỗ trợ nào.
Project thứ hai (DataAccess) là nơi cài đặt Entity Framework và chứa lớp context. Để xây dựng lớp context, DataAccess cũng phải tham chiếu sang Models. Nếu sử dụng Migration, bạn cần kích hoạt Migration trên project này.
Xây dựng các model
Mô hình EDM
Trong bài thực hành này chúng ta sẽ xây dựng mô hình EDM cho một bài toán quản lý trường học ở mức độ giản lược nhất.
Để các bạn dễ hình dung, các entity class sẽ được xây dựng theo sơ đồ dưới đây:
Theo sơ đồ trên, School là class mô phỏng cho thông tin về trường học. Trong mỗi School sẽ có nhiều khoa (Department), do đó tạo ra quan hệ 1-nhiều giữa School và Department.
Teacher là class mô tả cho giáo viên. Mỗi giáo viên cần thuộc về một Department. Đồng thời mỗi Department có nhiều giáo viên (Teacher). Do đó tạo ra quan hệ 1 – nhiều giữa Department và Teacher.
Student là class mô tả cho sinh viên. Specialization là class mô tả cho chuyên ngành của sinh viên. Mỗi sinh viên phải theo học một chuyên ngành nào đó. Do đó tạo ra quan hệ 1 – nhiều giữa Specialization và Student.
Cả Student và Teacher đều có quan hệ kế thừa từ Person (abstract class).
Mỗi giảng viên có thể giảng dạy nhiều lớp học (Course). Do đó tạo ra quan hệ 1 – nhiều giữa Teacher và Course.
Mỗi sinh viên sẽ theo nhiều lớp học. Mỗi lớp học phải có nhiều sinh viên. Do đó tạo ra quan hệ nhiều – nhiều giữa Student và Course.
Khi bạn đã hiểu sơ đồ trên, giờ là lúc bắt tay vào thực hiện.
Thực hành xây dựng các model class
Bước 1. Lần lượt thêm các class trong từng file code riêng biệt: Specialization (File Specialization.cs), School (file School.cs), Department (file Department.cs), Person (Person.cs), Student (Student.cs), Teacher (Teacher.cs), Gender (Gender.cs).
Bạn sẽ thu được cấu trúc file mã nguồn của Models như sau:
Lưu ý đặt tên class trùng với tên file code. Điều này sẽ giúp bạn quản lý mã nguồn dễ dàng hơn.
Bước 2. Viết code cho các class như sau:
namespace Models { public enum Gender : int { Male = 0, Female = 1, Unknown = 2 } }
using System; namespace Models { public abstract partial class Person { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string MiddleName { get; set; } public DateTime? DateOfBirth { get; set; } public Gender Gender { get; set; } } }
using System.Collections.Generic; namespace Models { public partial class Student : Person { public Student() { Courses = new HashSet<Course>(); } public string Group { get; set; } public virtual Specialization Specialization { get; set; } public virtual ICollection<Course> Courses { get; set; } } }
using System.Collections.Generic; namespace Models { public partial class Specialization { public Specialization() { Students = new HashSet<Student>(); } public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Student> Students { get; set; } } }
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace Models { public partial class Teacher : Person { public Teacher() { Courses = new HashSet<Course>(); } public string Qualification { get; set; } = "PhD"; public string Position { get; set; } = "Prof."; public bool IsDean { get; set; } = false; [Required] public virtual Department Department { get; set; } public virtual ICollection<Course> Courses { get; set; } } }
using System.Collections.Generic; namespace Models { public partial class School { public School() { this.Departments = new HashSet<Department>(); } public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Department> Departments { get; set; } } }
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace Models { public partial class Department { public Department() { this.Teachers = new HashSet<Teacher>(); } public int Id { get; set; } public string Name { get; set; } public string Office { get; set; } [Required] public virtual School School { get; set; } public virtual ICollection<Teacher> Teachers { get; set; } } }
using System.Collections.Generic; namespace Models { public partial class Course { public Course() { this.Students = new HashSet<Student>(); } public int Id { get; set; } public string Name { get; set; } public int Credit { get; set; } = 3; public string Description { get; set; } public virtual Teacher Teacher { get; set; } public virtual ICollection<Student> Students { get; set; } } }
Bước 3. Biên dịch Models.
Sau khi hoàn thành viết code hãy biên dịch Models (Ctrl + Shift + B).
Lưu ý: nếu bạn không biên dịch Models trước, khi chuyển sang DataAccess bạn sẽ không nhìn thấy các domain class vừa tạo.
Để ý rằng trong các class trên chúng ta hoàn toàn tuân thủ các quy ước của code-first. Điều này giúp tránh phải sử dụng đến Attribute hoặc Fluent API nếu không thực sự cần thiết.
Bạn cũng lưu ý, các navigation property chúng ta đều đặt từ khóa virtual để sử dụng cơ chế lazy loading của Entity Framework.
Các collection navigation property đều được khởi tạo sẵn trong constructor. Nó giúp bạn tránh được các NullException về sau.
Xây dựng DataAccess
Bước 1. Tạo class UniversityContext trong file tương ứng với code như sau:
using System.Data.Entity; using Models; namespace DataAccess { public class UniversityContext : DbContext { public UniversityContext() : base("name=UniversityContext") { } public virtual DbSet<Person> People { get; set; } public virtual DbSet<Department> Departments { get; set; } public virtual DbSet<School> Schools { get; set; } public virtual DbSet<Specialization> Specializations { get; set; } public virtual DbSet<Course> Courses { get; set; } } }
Lưu ý, nếu bạn thấy Intellisense không hỗ trợ với các model class, hãy build solution (Ctrl + Shift + B) trước.
Bước 2. Tạo mới node connectionStrings trong file App.config như sau:
<connectionStrings> <add name="UniversityContext" providerName="System.Data.SqlClient" connectionString="Data Source=(localdb)\mssqllocaldb;Initial Catalog=UniversityDatabase;Integrated Security=True"/> </connectionStrings>
Lưu ý điều chỉnh giá trị của connectionString cho phù hợp với server và cấu hình máy bạn.
Sau đây bạn có thể lựa chọn một trong hai hướng: sử dụng cơ chế Migration hoặc sử dụng Initializer (bộ khởi tạo).
Nếu sử dụng Migration
Bước 3. Kích hoạt Migration
Chạy lệnh enable-migrations từ dấu nhắc lệnh của Package Manager Console.
Lưu ý, để kích hoạt Migration thành công, bạn phải đặt DataAccess làm Startup Project.
Vấn đề nằm ở chỗ, trong constructor của UniversityContext chúng ta đang dùng cách khởi tạo CSDL với connectionString lưu trong file cấu hình:
public UniversityContext() : base("name=UniversityContext") { .. }
Mặc định Migration sẽ tìm kiếm connectionString có tên tương ứng (trong trường hợp này là UniversityContext) trong file cấu hình (App.config hoặc Web.config) của Startup project (tên được tô đậm hơn các project khác).
Bước 4. Thay đổi thông tin sau trong file Configuration.cs (thư mục Migrations)
AutomaticMigrationsEnabled = true; // chuyển giá trị thành true
Bước 5. Bổ sung một số dữ liệu ban đầu
Để có dữ liệu thử nghiệm, chúng ta nên tạo sẵn một số khi khởi tạo cơ sở dữ liệu.
Mở file Configuration.cs và viết lại phương thức Seed như sau:
namespace DataAccess.Migrations { using Models; using System; using System.Data.Entity; using System.Data.Entity.Migrations; using System.Linq; internal sealed class Configuration : DbMigrationsConfiguration<DataAccess.UniversityContext> { public Configuration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; } protected override void Seed(DataAccess.UniversityContext context) { // This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method // to avoid creating duplicate seed data. var hogwarts = new School { Name = "Hogwarts" }; context.Schools.AddOrUpdate(hogwarts); var departments = new Department[] { new Department { Name = "Information Technology", Office = "1011"}, new Department { Name = "Computer Science", Office = "1012"}, new Department { Name = "Networks and Commnunications", Office = "1013"} }; hogwarts.Departments = departments; context.Departments.AddOrUpdate(departments); var specializations = new Specialization[] { new Specialization { Name = "Computer Networks"}, new Specialization { Name = "Computer Systems"}, new Specialization { Name = "Computer Science"}, new Specialization { Name = "Cyber Security"}, }; context.Specializations.AddOrUpdate(specializations); var students = new Student[] { new Student { FirstName = "Harry", LastName = "Potter", Group = "Gryffindor", Specialization = specializations[0]}, new Student { FirstName = "Hermione", LastName = "Granger", Group = "Gryffindor", Specialization = specializations[0]}, new Student { FirstName = "Ron", LastName = "Weasley", Group = "Gryffindor", Specialization = specializations[0]}, new Student { FirstName = "Draco", LastName = "Malfoy", Group = "Slytherin", Specialization = specializations[1]}, new Student { FirstName = "Luna", LastName = "Lovegood", Group = "Ravenclaw", Specialization = specializations[1]}, new Student { FirstName = "Neville", LastName = "Longbottom", Group = "Gryffindor", Specialization = specializations[2]}, new Student { FirstName = "Cho", LastName = "Chang", Group = "Ravenclaw", Specialization = specializations[2]}, new Student { FirstName = "Percy", LastName = "Weasly", Group = "Gryffindor", Specialization = specializations[3]}, }; context.People.AddOrUpdate(students); var teachers = new Teacher[] { new Teacher { FirstName = "Severus", LastName = "Snape", Qualification = "PhD", Department = departments[0]}, new Teacher { FirstName = "Albus", LastName = "Dumbledore", Qualification = "PhD", Department = departments[0], IsDean = true}, new Teacher { FirstName = "Minerva", LastName = "McGonagall", Qualification = "PhD", Department = departments[1], IsDean = true}, new Teacher { FirstName = "Rubeus", LastName = "Hagrid", Qualification = "PhD", Department = departments[2], IsDean = true}, new Teacher { FirstName = "Argus", LastName = "Filch", Qualification = "PhD", Department = departments[2]}, new Teacher { FirstName = "Filius", LastName = "Flitwick", Qualification = "PhD", Department = departments[0]}, }; context.People.AddOrUpdate(teachers); var courses = new Course[] { new Course { Name = "Potions", Teacher = teachers[0], Students = students, Credit = 3 }, new Course { Name = "History of Magic", Teacher = teachers[1], Students = students, Credit = 4 }, new Course { Name = "Transfiguration", Teacher = teachers[2], Students = students, Credit = 3 }, new Course { Name = "Defence Against the Dark Arts", Teacher = teachers[0], Students = students, Credit = 5 }, new Course { Name = "Charms", Teacher = teachers[0], Students = students, Credit = 3 }, new Course { Name = "Astronomy", Teacher = teachers[1], Students = students, Credit = 4 }, new Course { Name = "Herbology", Teacher = teachers[3], Students = students, Credit = 4 }, new Course { Name = "Flying", Teacher = teachers[3], Students = students, Credit = 5 }, new Course { Name = "Arithmancy", Teacher = teachers[3], Students = students, Credit = 5 }, new Course { Name = "Muggle Studies", Teacher = teachers[4], Students = students, Credit = 2 }, new Course { Name = "Divination", Teacher = teachers[4], Students = students, Credit = 3 }, new Course { Name = "Study of Ancient Runes", Teacher = teachers[5], Students = students, Credit = 4 }, new Course { Name = "Care of Magical Creatures", Teacher = teachers[5], Students = students, Credit = 5 }, }; context.Courses.AddOrUpdate(courses); context.SaveChanges(); } } }
Sau khi xong bạn chạy lệnh update-database.
Bạn sẽ thu được cơ sở dữ liệu như sau:
Giờ nếu mở cơ sở dữ liệu ra bạn sẽ thấy dữ liệu đã được điền đầy đủ.
Bạn có thể để ý thấy là việc thêm dữ liệu vào nhìn khá là lằng nhằng, đặc biệt là ở những chỗ object có quan hệ với nhau. Đừng lo, đến chương sau chúng ta sẽ đi chi tiết vào vấn đề thêm dữ liệu.
Nếu sử dụng bộ khởi tạo
Bước 3. Tạo class khởi tạo DbInitializer trong file DbInitializer.cs và viết code như sau:
using System.Data.Entity; using Models; namespace DataAccess { public class DbInitializer : DropCreateDatabaseIfModelChanges<UniversityContext> { protected override void Seed(UniversityContext context) { var hogwarts = new School { Name = "Hogwarts" }; context.Schools.Add(hogwarts); var departments = new Department[] { new Department { Name = "Information Technology", Office = "1011"}, new Department { Name = "Computer Science", Office = "1012"}, new Department { Name = "Networks and Commnunications", Office = "1013"} }; hogwarts.Departments = departments; context.Departments.AddRange(departments); var specializations = new Specialization[] { new Specialization { Name = "Computer Networks"}, new Specialization { Name = "Computer Systems"}, new Specialization { Name = "Computer Science"}, new Specialization { Name = "Cyber Security"}, }; context.Specializations.AddRange(specializations); var students = new Student[] { new Student { FirstName = "Harry", LastName = "Potter", Group = "Gryffindor", Specialization = specializations[0]}, new Student { FirstName = "Hermione", LastName = "Granger", Group = "Gryffindor", Specialization = specializations[0]}, new Student { FirstName = "Ron", LastName = "Weasley", Group = "Gryffindor", Specialization = specializations[0]}, new Student { FirstName = "Draco", LastName = "Malfoy", Group = "Slytherin", Specialization = specializations[1]}, new Student { FirstName = "Luna", LastName = "Lovegood", Group = "Ravenclaw", Specialization = specializations[1]}, new Student { FirstName = "Neville", LastName = "Longbottom", Group = "Gryffindor", Specialization = specializations[2]}, new Student { FirstName = "Cho", LastName = "Chang", Group = "Ravenclaw", Specialization = specializations[2]}, new Student { FirstName = "Percy", LastName = "Weasly", Group = "Gryffindor", Specialization = specializations[3]}, }; context.People.AddRange(students); var teachers = new Teacher[] { new Teacher { FirstName = "Severus", LastName = "Snape", Qualification = "PhD", Department = departments[0]}, new Teacher { FirstName = "Albus", LastName = "Dumbledore", Qualification = "PhD", Department = departments[0], IsDean = true}, new Teacher { FirstName = "Minerva", LastName = "McGonagall", Qualification = "PhD", Department = departments[1], IsDean = true}, new Teacher { FirstName = "Rubeus", LastName = "Hagrid", Qualification = "PhD", Department = departments[2], IsDean = true}, new Teacher { FirstName = "Argus", LastName = "Filch", Qualification = "PhD", Department = departments[2]}, new Teacher { FirstName = "Filius", LastName = "Flitwick", Qualification = "PhD", Department = departments[0]}, }; context.People.AddRange(teachers); var courses = new Course[] { new Course { Name = "Potions", Teacher = teachers[0], Students = students, Credit = 3 }, new Course { Name = "History of Magic", Teacher = teachers[1], Students = students, Credit = 4 }, new Course { Name = "Transfiguration", Teacher = teachers[2], Students = students, Credit = 3 }, new Course { Name = "Defence Against the Dark Arts", Teacher = teachers[0], Students = students, Credit = 5 }, new Course { Name = "Charms", Teacher = teachers[0], Students = students, Credit = 3 }, new Course { Name = "Astronomy", Teacher = teachers[1], Students = students, Credit = 4 }, new Course { Name = "Herbology", Teacher = teachers[3], Students = students, Credit = 4 }, new Course { Name = "Flying", Teacher = teachers[3], Students = students, Credit = 5 }, new Course { Name = "Arithmancy", Teacher = teachers[3], Students = students, Credit = 5 }, new Course { Name = "Muggle Studies", Teacher = teachers[4], Students = students, Credit = 2 }, new Course { Name = "Divination", Teacher = teachers[4], Students = students, Credit = 3 }, new Course { Name = "Study of Ancient Runes", Teacher = teachers[5], Students = students, Credit = 4 }, new Course { Name = "Care of Magical Creatures", Teacher = teachers[5], Students = students, Credit = 5 }, }; context.Courses.AddRange(courses); context.SaveChanges(); } } }
Ở đây bạn xây dựng bộ khởi tạo riêng kế thừa từ DropCreateDatabaseIfModelChanges. Mỗi khi domain class thay đổi, cơ sở dữ liệu cũ sẽ bị xóa bỏ và tạo mới.
Bạn cũng ghi đè phương thức Seed để tạo dữ liệu bạn đầu với cùng những thông tin giống như phương thức Seed sử dụng trong Migration.
Nếu bạn muốn mỗi lần chạy chương trình sẽ tạo lại cơ sở dữ liệu mới (ví dụ, để dễ dàng thử nghiệm các tính năng cập nhật dữ liệu trong các bài học sau), bạn có thể cho DbInitializer kế thừa từ DropCreateDatabaseAlways.
Bước 4. Điều chỉnh hàm tạo của UniversityContext
public UniversityContext() : base("name=UniversityContext") { Database.SetInitializer(new DbInitializer()); }
Ở bước này bạn chỉ gọi thêm lệnh SetInitializer sử dụng class DbInitializer đã xây dựng ở bước 3.
Như bạn đã biết, bộ khởi tạo chỉ hoạt động nếu (1) bạn chạy chương trình và thực hiện truy vấn đầu tiên hoặc (2) bạn chủ động gọi lệnh Initialize ở chương trình (context.Database.Initialize(true);
).
Cơ sở dữ liệu bạn sẽ thu được trong trường hợp này giống như khi sử dụng migration với cùng dữ liệu ban đầu.
Tạo project ứng dụng
Đến đây thành phần truy xuất dữ liệu của solution đã hoàn thành. Bạn có thể sử dụng nó cho bất kỳ loại project ứng dụng nào (như Console, Windows Forms, Windows Presentation Foundation, ASP.NET).
Chúng ta sẽ minh họa bằng một project Console và một project Windows Forms.
Ứng dụng Console
Bước 1. Bổ sung thêm một project thuộc loại ConsoleApp vào solution và thiết lập để project này trở thành Startup project.
Bước 2. Tham chiếu đến Models và DataAccess.
Bước 3. Cài đặt Entity Framework cho project này.
Bước 4. Tạo node connectionString trong App.config như sau:
<connectionStrings> <add name="UniversityContext" providerName="System.Data.SqlClient" connectionString="Data Source=(localdb)\mssqllocaldb;Initial Catalog=UniversityDatabase;Integrated Security=True"/> </connectionStrings>
(bạn chỉ đơn giản copy node này từ App.config của DataAccess sang).
Bước 5. Viết code cho Program.cs như sau:
using System.Linq; using Models; using DataAccess; using static System.Console; namespace ConsoleApp { class Program { static void Main(string[] args) { Title = "Hogwarts School of Witchcraft and Wizardry"; using (var context = new UniversityContext()) { var teachers = context.People.Include("Courses").Include("Department").OfType<Teacher>().ToList(); WriteLine("### HOGWARTS STAFF ###"); foreach (var t in teachers) { WriteLine($" + {t.FirstName} {t.LastName}, {t.Qualification} at {t.Department.Name}"); if (t.Courses.Count > 0) { WriteLine(" Teaching coures:"); foreach (var c in t.Courses) { WriteLine($" -> {c.Name}"); } } } var students = context.People.OfType<Student>().ToList(); WriteLine("\r\n### BEST STUDENTS ###"); foreach (var s in students) { WriteLine($@" + {s.FirstName} {s.LastName}{(string.IsNullOrEmpty(s.Group) ? "" : $" from {s.Group}")}"); } } ReadLine(); } } }
Kết quả chạy chương trình:
Ứng dụng Windows Forms
Chúng ta xây dựng một ứng dụng windows forms đơn giản để minh họa khả năng của Entity Framework.
Bước 1. Tạo một project mới trong solution thuộc loại Windows Forms và đặt làm Startup Project.
Thực hiện các bước giống như bước 2-3-4-5 đã thực hiện ở ConsoleApp bên trên.
Bước 2. Tạo Data Source cho project từ các model class
Mở tab Data Sources và click vào nút Add New Data Source và thực hiện theo các bước sau
Bước 3. Kéo thả các Data Source Teacher và Student vào giao diện thiết kế của Form1. Thực hiện các thiết kế tùy ý bạn.
Mở file code behind và code lại như sau:
using System.Data.Entity; using System.Linq; using System.Windows.Forms; using DataAccess; using Models; namespace WindowsFormsApp { public partial class Form1 : Form { private readonly UniversityContext _context = new UniversityContext(); public Form1() { InitializeComponent(); _context.People.Load(); teacherBindingSource.DataSource = _context.People.Local.OfType<Teacher>(); studentBindingSource.DataSource = _context.People.Local.OfType<Student>(); } } }
Chạy chương trình sẽ thu được kết quả như sau:
Bạn đã thu được một chương trình windows forms đơn giản sử dụng Entity Framework.
Chúng ta sẽ không đi sâu chi tiết về windows forms trong bài học này. Nếu bạn muốn học thêm về cách thiết kế và sử dụng windows forms, hãy đọc loạt bài giải pháp windows forms trên site. Nếu gặp khó khăn khi thực hiện bạn có thể tải mã nguồn solution để tham khảo (đường link ở cuối bài).
Kết luận
Trong bài học này chúng ta đã thiết kế một EDM hoàn thiện sử dụng code first và sử dụng nó trong hai project ứng dụng.
Bạn để ý cách thức tổ chức solution (với Models và DataAccess). Cách tổ chức solution này cho phép bạn tái sử dụng thành phần truy xuất dữ liệu ở nhiều project ứng dụng khác nhau.
[wpdm_package id=’11644′]
+ Nếu bạn thấy site hữu ích, trước khi rời đi hãy giúp đỡ site bằng một hành động nhỏ để site có thể phát triển và phục vụ bạn tốt hơn.
+ Nếu bạn thấy bài viết hữu ích, hãy giúp chia sẻ tới mọi người.
+ Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần thảo luận cuối trang.
Cảm ơn bạn!
[/signinlocker]
Em đang gặp lỗi error như sau
No connection string named ‘UniversityContext’ could be found in the application config file.
PM>
Em chưa fix được, mong mọi người giúp đỡ
Bạn chưa thực hiện bước 2, phần Xây dựng DataAccess.
Dạ chào chị Mai Chi, chị cho em hỏi Giả sử trong Project DataAccess có 2 lớp class là Repos(Xây dựng chức năng) còn class DataAccess để chứa List<Students> [*] và Lớp Repos mũi tên đứt sang Class DataAccess . Vậy chúng ta cần xây dựng biến gì để sử dụng nó hay không ạ?
Ý bạn là sơ đồ UML của class có quan hệ biểu diễn bằng mũi tên đứt phải không ạ? Quan hệ này chỉ thể hiện rằng trong lớp Repo có sử dụng object của DataAccess thôi.
Dạ đúng r ạ, mũi tiên nét đứt ạ