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 ที่พิมพ์ สำหรับแต่ละชั้นเรียนในรุ่นของเรา ต่อไปนี้คือการนำไปใช้กับคลาส MyContext ซึ่งได้มาจากคลาส DbContext

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; }
}