Entity Framework - ตัวอย่างแรก
มากำหนดโมเดลง่ายๆโดยใช้คลาส เรากำลังกำหนดสิ่งเหล่านี้ในไฟล์ Program.cs แต่ในแอปพลิเคชันในโลกแห่งความเป็นจริงคุณจะแบ่งชั้นเรียนของคุณออกเป็นไฟล์แยกกันและอาจเป็นโครงการแยกต่างหาก ต่อไปนี้เป็นแบบจำลองข้อมูลที่เราจะสร้างโดยใช้แนวทาง Code First
สร้างแบบจำลอง
เพิ่มสามคลาสต่อไปนี้ในไฟล์ Program.cs โดยใช้รหัสต่อไปนี้สำหรับคลาสนักเรียน
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
คุณสมบัติ ID จะกลายเป็นคอลัมน์คีย์หลักของตารางฐานข้อมูลที่สอดคล้องกับคลาสนี้
คุณสมบัติการลงทะเบียนเป็นคุณสมบัติการนำทาง คุณสมบัติการนำทางถือเอนทิตีอื่น ๆ ที่เกี่ยวข้องกับเอนทิตีนี้
ในกรณีนี้คุณสมบัติการลงทะเบียนของเอนทิตีนักศึกษาจะเก็บเอนทิตีการลงทะเบียนทั้งหมดที่เกี่ยวข้องกับเอนทิตีนักศึกษานั้น
โดยทั่วไปคุณสมบัติการนำทางถูกกำหนดให้เป็นเสมือนเพื่อให้สามารถใช้ประโยชน์จากฟังก์ชันการทำงานของ Entity Framework บางอย่างเช่นการโหลดแบบขี้เกียจ
หากคุณสมบัติการนำทางสามารถเก็บเอนทิตีได้หลายรายการ (เช่นเดียวกับความสัมพันธ์แบบกลุ่มต่อกลุ่มหรือแบบกลุ่มเดียว) ประเภทของคุณสมบัตินั้นจะต้องเป็นรายการที่สามารถเพิ่มลบและอัปเดตรายการได้เช่น ICollection
ต่อไปนี้คือการใช้งานสำหรับชั้นเรียนหลักสูตร
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
คุณสมบัติการลงทะเบียนเป็นคุณสมบัติการนำทาง เอนทิตีหลักสูตรสามารถเกี่ยวข้องกับเอนทิตีการลงทะเบียนจำนวนเท่าใดก็ได้
ต่อไปนี้คือการใช้งานสำหรับคลาสการลงทะเบียนและ enum
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
คุณสมบัติ EnrollmentID จะเป็นคีย์หลัก
คุณสมบัติเกรดคือ enum เครื่องหมายคำถามหลังการประกาศประเภทเกรดบ่งชี้ว่าคุณสมบัติเกรดเป็นโมฆะ
เกรดที่เป็นโมฆะจะแตกต่างจากเกรดศูนย์ Null หมายถึงเกรดที่ยังไม่ทราบหรือยังไม่ได้รับมอบหมาย
คุณสมบัติ StudentID และ CourseID เป็นคีย์ต่างประเทศและคุณสมบัติการนำทางที่เกี่ยวข้องคือ Student และ Course
เอนทิตีการลงทะเบียนเชื่อมโยงกับนักเรียนหนึ่งคนและเอนทิตีหลักสูตรหนึ่งหน่วยงานดังนั้นคุณสมบัติจึงสามารถเก็บเอนทิตีนักเรียนและหลักสูตรเดียวเท่านั้น
สร้างบริบทฐานข้อมูล
คลาสหลักที่ประสานการทำงานของ Entity Framework สำหรับโมเดลข้อมูลที่กำหนดคือคลาสบริบทฐานข้อมูลซึ่งอนุญาตให้สอบถามและบันทึกข้อมูล คุณสามารถสร้างคลาสนี้โดยได้มาจากคลาส DbContext และเปิดเผย DbSet ที่พิมพ์
public class MyContext : DbContext {
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
ต่อไปนี้เป็นรหัสที่สมบูรณ์ในไฟล์ Program.cs
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFCodeFirstDemo {
class Program {
static void Main(string[] args) {}
}
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class MyContext : DbContext {
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
}
โค้ดด้านบนคือทั้งหมดที่เราต้องใช้ในการเริ่มจัดเก็บและดึงข้อมูล มาเพิ่มข้อมูลแล้วดึงข้อมูล ต่อไปนี้เป็นรหัสในวิธีการหลัก
static void Main(string[] args) {
using (var context = new MyContext()) {
// Create and save a new Students
Console.WriteLine("Adding new students");
var student = new Student {
FirstMidName = "Alain", LastName = "Bomer",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student);
var student1 = new Student {
FirstMidName = "Mark", LastName = "Upston",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student1);
context.SaveChanges();
// Display all Students from the database
var students = (from s in context.Students
orderby s.FirstMidName select s).ToList<Student>();
Console.WriteLine("Retrieve all Students from the database:");
foreach (var stdnt in students) {
string name = stdnt.FirstMidName + " " + stdnt.LastName;
Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
เมื่อดำเนินการโค้ดด้านบนคุณจะได้รับผลลัพธ์ต่อไปนี้
Adding new students
Retrieve all Students from the database:
ID: 1, Name: Alain Bomer
ID: 2, Name: Mark Upston
Press any key to exit...
คำถามที่อยู่ในใจคือข้อมูลและฐานข้อมูลอยู่ที่ไหนซึ่งเราได้เพิ่มข้อมูลบางส่วนแล้วดึงมาจากฐานข้อมูล ตามแบบแผน DbContext ได้สร้างฐานข้อมูลสำหรับคุณ
หากอินสแตนซ์ SQL Express ในเครื่องพร้อมใช้งาน Code First ได้สร้างฐานข้อมูลบนอินสแตนซ์นั้น
หาก SQL Express ไม่พร้อมใช้งาน Code First จะลองใช้ LocalDb
ฐานข้อมูลถูกตั้งชื่อตามชื่อแบบเต็มของบริบทที่ได้รับ
ในกรณีของเราอินสแตนซ์ SQL Express พร้อมใช้งานและชื่อฐานข้อมูลคือ EFCodeFirstDemo.MyContext ดังแสดงในภาพต่อไปนี้
นี่เป็นเพียงข้อตกลงเริ่มต้นและมีหลายวิธีในการเปลี่ยนฐานข้อมูลที่ Code First ใช้
ดังที่คุณเห็นในภาพด้านบนมันได้สร้างตารางนักเรียนหลักสูตรและการลงทะเบียนและแต่ละตารางประกอบด้วยคอลัมน์ที่มีประเภทข้อมูลและความยาวที่เหมาะสม
ชื่อคอลัมน์และประเภทข้อมูลยังตรงกับคุณสมบัติของคลาสโดเมนที่เกี่ยวข้อง
การเริ่มต้นฐานข้อมูล
ในตัวอย่างข้างต้นเราได้เห็นว่า Code First สร้างฐานข้อมูลโดยอัตโนมัติ แต่ถ้าคุณต้องการเปลี่ยนชื่อฐานข้อมูลและเซิร์ฟเวอร์ให้เราดูว่า Code First ตัดสินใจชื่อฐานข้อมูลและเซิร์ฟเวอร์อย่างไรในขณะที่เริ่มต้นฐานข้อมูล ดูแผนภาพต่อไปนี้
คุณสามารถกำหนดตัวสร้างพื้นฐานของคลาสบริบทได้ด้วยวิธีต่อไปนี้
- ไม่มีพารามิเตอร์
- ชื่อฐานข้อมูล
- ชื่อสตริงการเชื่อมต่อ
ไม่มีพารามิเตอร์
หากคุณระบุคอนสตรัคเตอร์พื้นฐานของคลาสบริบทโดยไม่มีพารามิเตอร์ใด ๆ ดังที่แสดงในตัวอย่างด้านบนเอนทิตีเฟรมเวิร์กจะสร้างฐานข้อมูลในเซิร์ฟเวอร์ SQLEXPRESS ในเครื่องของคุณโดยใช้ชื่อ {Namespace} {ชื่อคลาสบริบท}
ในตัวอย่างข้างต้นฐานข้อมูลที่สร้างขึ้นโดยอัตโนมัติมีชื่อ EFCodeFirstDemo.MyContext หากคุณดูชื่อคุณจะพบว่า EFCodeFirstDemo คือเนมสเปซและ MyContext คือชื่อคลาสบริบทดังที่แสดงในโค้ดต่อไปนี้
public class MyContext : DbContext {
public MyContext() : base() {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
ชื่อฐานข้อมูล
หากคุณส่งชื่อฐานข้อมูลเป็นพารามิเตอร์ในคอนสตรัคเตอร์พื้นฐานของคลาสบริบท Code First จะสร้างฐานข้อมูลโดยอัตโนมัติอีกครั้ง แต่คราวนี้ชื่อจะถูกส่งเป็นพารามิเตอร์ในตัวสร้างฐานบนเซิร์ฟเวอร์ฐานข้อมูล SQLEXPRESS ในเครื่อง .
ในโค้ดต่อไปนี้ MyContextDB ถูกระบุเป็นพารามิเตอร์ในตัวสร้างฐาน หากเรียกใช้แอปพลิเคชันของคุณฐานข้อมูลที่มีชื่อ MyContextDB จะถูกสร้างขึ้นในเซิร์ฟเวอร์ SQL ภายในของคุณ
public class MyContext : DbContext {
public MyContext() : base("MyContextDB") {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
ชื่อสตริงการเชื่อมต่อ
นี่เป็นวิธีง่ายๆในการบอกให้ DbContext ใช้เซิร์ฟเวอร์ฐานข้อมูลอื่นที่ไม่ใช่ SQL Express หรือ LocalDb คุณสามารถเลือกที่จะใส่สตริงการเชื่อมต่อในไฟล์ app.config ของคุณ
หากชื่อของสตริงการเชื่อมต่อตรงกับชื่อของบริบทของคุณ (ไม่ว่าจะมีหรือไม่มีคุณสมบัติเนมสเปซก็ตาม) DbContext จะพบเมื่อพารามิเตอร์น้อยกว่าตัวสร้างถูกใช้
หากชื่อสตริงการเชื่อมต่อแตกต่างจากชื่อบริบทของคุณคุณสามารถบอกให้ DbContext ใช้การเชื่อมต่อนี้ในโหมด Code First โดยส่งชื่อสตริงการเชื่อมต่อไปยังตัวสร้าง DbContext
public class MyContext : DbContext {
public MyContext() : base("name = MyContextDB") {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
ในโค้ดด้านบนข้อมูลโค้ดของสตริงการเชื่อมต่อคลาสบริบทถูกระบุเป็นพารามิเตอร์ในตัวสร้างพื้นฐาน
ชื่อสตริงการเชื่อมต่อต้องขึ้นต้นด้วย "name =" มิฉะนั้นจะถือว่าเป็นชื่อฐานข้อมูล
แบบฟอร์มนี้ทำให้ชัดเจนว่าคุณคาดว่าจะพบสตริงการเชื่อมต่อในไฟล์กำหนดค่าของคุณ ข้อยกเว้นจะเกิดขึ้นหากไม่พบสตริงการเชื่อมต่อที่มีชื่อที่กำหนด
<connectionStrings>
<add name = "MyContextDB"
connectionString = "Data Source =.;Initial Catalog = EFMyContextDB;Integrated Security = true"
providerName = "System.Data.SqlClient"/>
</connectionStrings>
ชื่อฐานข้อมูลในสตริงการเชื่อมต่อใน app.config คือ EFMyContextDB. CodeFirst จะสร้างไฟล์EFMyContextDB ฐานข้อมูลหรือใช้ที่มีอยู่ EFMyContextDB ฐานข้อมูลที่ SQL Server ในเครื่อง
คลาสโดเมน
จนถึงตอนนี้เราเพิ่งปล่อยให้ EF ค้นพบโมเดลโดยใช้รูปแบบเริ่มต้น แต่จะมีบางครั้งที่ชั้นเรียนของเราไม่เป็นไปตามอนุสัญญาและเราจำเป็นต้องสามารถกำหนดค่าเพิ่มเติมได้ แต่คุณสามารถลบล้างข้อตกลงเหล่านี้ได้โดยกำหนดค่าคลาสโดเมนของคุณเพื่อให้ EF มีข้อมูลที่จำเป็น มีสองตัวเลือกในการกำหนดค่าคลาสโดเมนของคุณ -
- คำอธิบายประกอบข้อมูล
- API ที่คล่องแคล่ว
คำอธิบายประกอบข้อมูล
DataAnnotations ใช้เพื่อกำหนดค่าคลาสของคุณซึ่งจะเน้นการกำหนดค่าที่จำเป็นโดยทั่วไป นอกจากนี้ DataAnnotations ยังเข้าใจโดยแอปพลิเคชัน. NET จำนวนมากเช่น ASP.NET MVC ซึ่งอนุญาตให้แอปพลิเคชันเหล่านี้ใช้ประโยชน์จากคำอธิบายประกอบเดียวกันสำหรับการตรวจสอบความถูกต้องฝั่งไคลเอ็นต์
ต่อไปนี้เป็นคำอธิบายประกอบข้อมูลที่ใช้ในชั้นเรียนของนักเรียน
public class Enrollment {
[Key]
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
[ForeignKey("CourseID")]
public virtual Course Course { get; set; }
[ForeignKey("ID")]
public virtual Student Student { get; set; }
}
API ที่คล่องแคล่ว
การกำหนดค่าโมเดลส่วนใหญ่สามารถทำได้โดยใช้คำอธิบายประกอบข้อมูลอย่างง่าย Fluent API เป็นวิธีขั้นสูงในการระบุการกำหนดค่าโมเดลที่ครอบคลุมทุกสิ่งที่คำอธิบายประกอบข้อมูลทำได้นอกเหนือจากการกำหนดค่าขั้นสูงบางอย่างที่ไม่สามารถทำได้ด้วยคำอธิบายประกอบข้อมูล คำอธิบายประกอบข้อมูลและ API ที่คล่องแคล่วสามารถใช้ร่วมกันได้
ในการเข้าถึง API ที่คล่องแคล่วคุณจะแทนที่เมธอด OnModelCreating ใน DbContext ตอนนี้ขอเปลี่ยนชื่อคอลัมน์ในตารางนักเรียนจาก FirstMidName เป็น FirstName ตามที่แสดงในโค้ดต่อไปนี้
public class MyContext : DbContext {
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
.HasColumnName("FirstName");
}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}