Entity Framework - คู่มือฉบับย่อ

Entity Framework คืออะไร?

Entity Framework เปิดตัวครั้งแรกในปี 2008 ซึ่งเป็นวิธีการหลักของ Microsoft ในการโต้ตอบระหว่างแอปพลิเคชัน. NET และฐานข้อมูลเชิงสัมพันธ์ Entity Framework คือ Object Relational Mapper (ORM) ซึ่งเป็นเครื่องมือประเภทหนึ่งที่ช่วยลดความซับซ้อนในการแมประหว่างอ็อบเจ็กต์ในซอฟต์แวร์ของคุณไปยังตารางและคอลัมน์ของฐานข้อมูลเชิงสัมพันธ์

  • Entity Framework (EF) เป็นกรอบโอเพนซอร์ส ORM สำหรับ ADO.NET ซึ่งเป็นส่วนหนึ่งของ. NET Framework

  • ORM ดูแลการสร้างการเชื่อมต่อฐานข้อมูลและดำเนินการคำสั่งตลอดจนรับผลการสืบค้นและกำหนดผลลัพธ์เหล่านั้นเป็นวัตถุแอปพลิเคชันของคุณโดยอัตโนมัติ

  • ORM ยังช่วยติดตามการเปลี่ยนแปลงของออบเจ็กต์เหล่านั้นและเมื่อได้รับคำแนะนำก็จะยังคงมีการเปลี่ยนแปลงเหล่านั้นกลับไปยังฐานข้อมูลให้คุณ

ทำไมต้องเป็น Entity Framework

Entity Framework คือ ORM และ ORM มีวัตถุประสงค์เพื่อเพิ่มประสิทธิภาพการทำงานของนักพัฒนาโดยลดงานที่ซ้ำซ้อนในการคงข้อมูลที่ใช้ในแอปพลิเคชัน

  • Entity Framework สามารถสร้างคำสั่งฐานข้อมูลที่จำเป็นสำหรับการอ่านหรือเขียนข้อมูลในฐานข้อมูลและดำเนินการให้คุณ

  • หากคุณกำลังค้นหาคุณสามารถแสดงคำค้นหาของคุณเทียบกับวัตถุโดเมนของคุณโดยใช้ LINQ กับเอนทิตี

  • Entity Framework จะดำเนินการค้นหาที่เกี่ยวข้องในฐานข้อมูลจากนั้นสร้างผลลัพธ์เป็นอินสแตนซ์ของอ็อบเจ็กต์โดเมนของคุณเพื่อให้คุณทำงานภายในแอพของคุณ

มี ORM อื่น ๆ ในตลาดเช่น NHibernate และ LLBLGen Pro โดยทั่วไป ORM ส่วนใหญ่จะแมปประเภทโดเมนกับสคีมาฐานข้อมูลโดยตรง

Entity Framework มีเลเยอร์การแมปที่ละเอียดขึ้นเพื่อให้คุณสามารถปรับแต่งการแม็พได้เองตัวอย่างเช่นโดยการแม็พเอนทิตีเดียวกับตารางฐานข้อมูลหลายตารางหรือแม้แต่เอนทิตีหลายรายการกับตารางเดียว

  • Entity Framework เป็นเทคโนโลยีการเข้าถึงข้อมูลที่แนะนำสำหรับแอปพลิเคชันใหม่ของ Microsoft

  • ADO.NET ดูเหมือนจะอ้างถึงเทคโนโลยีสำหรับชุดข้อมูลและตารางข้อมูลโดยตรง

  • Entity Framework คือที่ที่มีการลงทุนแบบก้าวไปข้างหน้าทั้งหมดซึ่งเป็นกรณีนี้มาหลายปีแล้ว

  • Microsoft แนะนำให้คุณใช้ Entity Framework บน ADO.NET หรือ LINQ กับ SQL สำหรับการพัฒนาใหม่ทั้งหมด

รูปแบบความคิด

สำหรับนักพัฒนาที่คุ้นเคยกับการพัฒนาที่เน้นฐานข้อมูลการเปลี่ยนแปลงที่ยิ่งใหญ่ที่สุดของ Entity Framework คือการช่วยให้คุณมุ่งเน้นไปที่โดเมนธุรกิจของคุณ คุณต้องการให้แอปพลิเคชันของคุณทำอะไรโดยไม่ถูก จำกัด โดยสิ่งที่ฐานข้อมูลสามารถทำได้?

  • ด้วย Entity Framework จุดโฟกัสจะเรียกว่าแบบจำลองแนวคิด เป็นแบบจำลองของวัตถุในแอปพลิเคชันของคุณไม่ใช่แบบจำลองของฐานข้อมูลที่คุณใช้เพื่อคงข้อมูลแอปพลิเคชันของคุณ

  • แบบจำลองแนวคิดของคุณอาจเกิดขึ้นเพื่อให้สอดคล้องกับสคีมาฐานข้อมูลของคุณหรืออาจแตกต่างกันมาก

  • คุณสามารถใช้ Visual Designer เพื่อกำหนดแบบจำลองแนวคิดของคุณซึ่งจะสามารถสร้างคลาสที่คุณจะใช้ในแอปพลิเคชันของคุณในท้ายที่สุด

  • คุณสามารถกำหนดคลาสของคุณและใช้คุณสมบัติของ Entity Framework ที่เรียกว่า Code First จากนั้น Entity Framework จะเข้าใจรูปแบบแนวคิด

ไม่ว่าจะด้วยวิธีใด Entity Framework จะหาวิธีย้ายจากแบบจำลองแนวคิดของคุณไปยังฐานข้อมูลของคุณ ดังนั้นคุณสามารถสอบถามกับวัตถุโมเดลแนวความคิดของคุณและทำงานกับวัตถุเหล่านั้นได้โดยตรง

คุณสมบัติ

ต่อไปนี้เป็นคุณสมบัติพื้นฐานของ Entity Framework รายการนี้สร้างขึ้นตามคุณสมบัติที่โดดเด่นที่สุดและจากคำถามที่พบบ่อยเกี่ยวกับ Entity Framework

  • Entity Framework เป็นเครื่องมือของ Microsoft
  • Entity Framework กำลังได้รับการพัฒนาเป็นผลิตภัณฑ์ Open Source
  • Entity Framework ไม่เชื่อมโยงหรือขึ้นอยู่กับรอบการเผยแพร่. NET อีกต่อไป
  • ทำงานร่วมกับฐานข้อมูลเชิงสัมพันธ์กับผู้ให้บริการ Entity Framework ที่ถูกต้อง
  • การสร้างคำสั่ง SQL จาก LINQ ไปยังเอนทิตี
  • Entity Framework จะสร้างแบบสอบถามที่กำหนดพารามิเตอร์
  • ติดตามการเปลี่ยนแปลงวัตถุในหน่วยความจำ
  • อนุญาตให้แทรกอัปเดตและลบการสร้างคำสั่ง
  • ทำงานร่วมกับโมเดลภาพหรือกับชั้นเรียนของคุณเอง
  • Entity Framework ได้จัดเก็บ Procedure Support

สถาปัตยกรรมของ Entity Framework จากล่างขึ้นบนประกอบด้วยสิ่งต่อไปนี้ -

ผู้ให้บริการข้อมูล

สิ่งเหล่านี้เป็นผู้ให้บริการเฉพาะต้นทางซึ่งเป็นนามธรรมของอินเทอร์เฟซ ADO.NET เพื่อเชื่อมต่อกับฐานข้อมูลเมื่อเขียนโปรแกรมกับสคีมาแนวความคิด

จะแปลภาษา SQL ทั่วไปเช่น LINQ ผ่านทางทรีคำสั่งเป็นนิพจน์ SQL ดั้งเดิมและดำเนินการกับระบบ DBMS เฉพาะ

ไคลเอนต์เอนทิตี

เลเยอร์นี้แสดงเลเยอร์เอนทิตีไปที่เลเยอร์บน ไคลเอนต์เอนทิตีให้ความสามารถสำหรับนักพัฒนาในการทำงานกับเอนทิตีในรูปแบบของแถวและคอลัมน์โดยใช้เคียวรี SQL เอนทิตีโดยไม่จำเป็นต้องสร้างคลาสเพื่อแสดงสคีมาแนวคิด ไคลเอนต์เอนทิตีแสดงเลเยอร์เฟรมเวิร์กเอนทิตีซึ่งเป็นฟังก์ชันหลัก เลเยอร์เหล่านี้เรียกว่าแบบจำลองข้อมูลเอนทิตี

  • Storage Layer มีสกีมาฐานข้อมูลทั้งหมดในรูปแบบ XML

  • Entity Layer ซึ่งเป็นไฟล์ XML กำหนดเอนทิตีและความสัมพันธ์

  • Mapping layer เป็นไฟล์ XML ที่แมปเอนทิตีและความสัมพันธ์ที่กำหนดไว้ที่เลเยอร์แนวคิดด้วยความสัมพันธ์จริงและตารางที่กำหนดไว้ที่เลเยอร์ตรรกะ

  • Metadata services ซึ่งแสดงใน Entity Client ยังให้ API แบบรวมศูนย์เพื่อเข้าถึงเมทาดาทาที่จัดเก็บเลเยอร์เอนทิตีการแมปและที่เก็บข้อมูล

บริการวัตถุ

เลเยอร์ Object Services คือ Object Context ซึ่งแสดงถึงเซสชันของการโต้ตอบระหว่างแอ็พพลิเคชันและแหล่งข้อมูล

  • การใช้ Object Context หลักคือการดำเนินการต่างๆเช่นเพิ่มลบอินสแตนซ์ของเอนทิตีและบันทึกสถานะที่เปลี่ยนแปลงกลับไปยังฐานข้อมูลด้วยความช่วยเหลือของแบบสอบถาม

  • เป็นเลเยอร์ ORM ของ Entity Framework ซึ่งแสดงถึงผลลัพธ์ข้อมูลไปยังอินสแตนซ์ออบเจ็กต์ของเอนทิตี

  • บริการนี้ช่วยให้นักพัฒนาสามารถใช้คุณสมบัติ ORM ที่สมบูรณ์เช่นการแมปคีย์หลักการติดตามการเปลี่ยนแปลง ฯลฯ โดยการเขียนแบบสอบถามโดยใช้ LINQ และ Entity SQL

มีอะไรใหม่ใน Entity Framework 6

Framework มี API ที่ซับซ้อนซึ่งช่วยให้คุณสามารถควบคุมทุกอย่างได้อย่างละเอียดตั้งแต่การสร้างแบบจำลองไปจนถึงพฤติกรรมรันไทม์ ส่วนหนึ่งของ Entity Framework 5 อยู่ภายใน. NET และอีกส่วนหนึ่งอาศัยอยู่ในชุดประกอบเพิ่มเติมที่แจกจ่ายโดยใช้ NuGet

  • ฟังก์ชันหลักของ Entity Framework ถูกสร้างขึ้นใน. NET Framework

  • การสนับสนุน Code First นั่นคือสิ่งที่ช่วยให้ Entity Framework ใช้คลาสแทนโมเดลภาพและ API วิธีที่เบากว่าสำหรับการโต้ตอบกับ EF อยู่ในแพ็คเกจ NuGet

  • แกนหลักคือสิ่งที่ให้การสืบค้นการติดตามการเปลี่ยนแปลงและการเปลี่ยนแปลงทั้งหมดจากการสืบค้นของคุณไปเป็นแบบสอบถาม SQL รวมทั้งจากข้อมูลที่ส่งกลับไปยังวัตถุ

  • คุณสามารถใช้แพ็คเกจ EF 5 NuGet กับทั้ง. NET 4 และ. NET 4.5

  • จุดสำคัญจุดหนึ่งของความสับสน -. NET 4.5 ได้เพิ่มการรองรับ enums และข้อมูลเชิงพื้นที่ให้กับ Entity Framework API หลักซึ่งหมายความว่าหากคุณใช้ EF 5 กับ. NET 4 คุณจะไม่ได้รับคุณสมบัติใหม่เหล่านี้ คุณจะได้รับเมื่อรวม EF5 กับ. NET 4.5 เท่านั้น

ตอนนี้เรามาดู Entity Framework 6 กันดีกว่าตอนนี้ API หลักที่อยู่ใน. NET ใน Entity Framework 6 เป็นส่วนหนึ่งของแพ็คเกจ NuGet

มันหมายความว่า -

  • Entity Framework ทั้งหมดอยู่ภายในชุดประกอบนี้ซึ่งจัดจำหน่ายโดย NuGet

  • คุณจะไม่ต้องพึ่งพา. NET ในการจัดหาคุณลักษณะเฉพาะเช่นการสนับสนุน Entity Framework enum และการสนับสนุนข้อมูลพิเศษ

  • คุณจะเห็นว่าคุณสมบัติอย่างหนึ่งของ EF6 คือรองรับ enums และข้อมูลเชิงพื้นที่สำหรับ. NET 4

ในการเริ่มทำงานกับ Entity Framework คุณต้องติดตั้งเครื่องมือการพัฒนาต่อไปนี้ -

  • Visual Studio 2013 ขึ้นไป
  • SQL Server 2012 ขึ้นไป
  • การอัปเดต Entity Framework จาก NuGet Package

ไมโครซอฟท์ยังมีรุ่นฟรีของสตูดิโอภาพซึ่งยังมี SQL Server และสามารถดาวน์โหลดได้จากwww.visualstudio.com

การติดตั้ง

Step 1- เมื่อดาวน์โหลดเสร็จแล้วให้เรียกใช้โปรแกรมติดตั้ง กล่องโต้ตอบต่อไปนี้จะปรากฏขึ้น

Step 2 - คลิกที่ปุ่มติดตั้งและจะเริ่มกระบวนการติดตั้ง

Step 3- เมื่อขั้นตอนการติดตั้งเสร็จสมบูรณ์คุณจะเห็นกล่องโต้ตอบต่อไปนี้ ปิดกล่องโต้ตอบนี้และรีสตาร์ทคอมพิวเตอร์หากจำเป็น

Step 4- เปิด Visual Studio จากเมนูเริ่มซึ่งจะเปิดกล่องโต้ตอบต่อไปนี้ จะเป็นครั้งแรกสำหรับการเตรียมการ

Step 5 - เมื่อเสร็จแล้วคุณจะเห็นหน้าต่างหลักของ Visual studio

มาสร้างโปรเจ็กต์ใหม่จากไฟล์→ใหม่→โปรเจ็กต์

Step 1 - เลือก Console Application แล้วคลิกปุ่ม OK

Step 2 - ในโซลูชัน Explorer ให้คลิกขวาที่โครงการของคุณ

Step 3 - เลือก Manage NuGet Packages ตามที่แสดงในภาพด้านบนซึ่งจะเปิดหน้าต่างต่อไปนี้ใน Visual Studio

Step 4 - ค้นหา Entity Framework และติดตั้งเวอร์ชันล่าสุดโดยกดปุ่มติดตั้ง

Step 5- คลิกตกลง เมื่อติดตั้งเสร็จแล้วคุณจะเห็นข้อความต่อไปนี้ในหน้าต่างผลลัพธ์ของคุณ

ตอนนี้คุณพร้อมที่จะเริ่มแอปพลิเคชันของคุณ

ในบทช่วยสอนนี้เราจะใช้ฐานข้อมูลมหาวิทยาลัยอย่างง่าย ฐานข้อมูลของมหาวิทยาลัยอาจมีความซับซ้อนมากขึ้นโดยรวม แต่เพื่อการสาธิตและการเรียนรู้เรากำลังใช้รูปแบบที่ง่ายที่สุดของฐานข้อมูลนี้ แผนภาพต่อไปนี้ประกอบด้วยสามตาราง

  • Student
  • Course
  • Enrollment

เมื่อใดก็ตามที่มีการใช้ฐานข้อมูลคำสิ่งหนึ่งที่เข้ามาในใจของเราโดยตรงและนั่นก็คือตารางประเภทต่างๆที่มีความสัมพันธ์กัน มีความสัมพันธ์สามประเภทระหว่างตารางและความสัมพันธ์ระหว่างตารางต่างๆขึ้นอยู่กับวิธีกำหนดคอลัมน์ที่เกี่ยวข้อง

  • ความสัมพันธ์แบบหนึ่งต่อกลุ่ม
  • ความสัมพันธ์แบบกลุ่มต่อกลุ่ม
  • ความสัมพันธ์แบบหนึ่งต่อหนึ่ง

ความสัมพันธ์แบบหนึ่งต่อกลุ่ม

ความสัมพันธ์แบบหนึ่งต่อกลุ่มเป็นประเภทความสัมพันธ์ที่พบบ่อยที่สุด ในความสัมพันธ์ประเภทนี้แถวในตาราง A สามารถมีแถวที่ตรงกันได้หลายแถวในตาราง B แต่แถวในตาราง B สามารถมีแถวที่ตรงกันเพียงแถวเดียวในตาราง A ตัวอย่างเช่นในแผนภาพด้านบนตารางนักเรียนและตารางการลงทะเบียนมีหนึ่งแถว - ความสัมพันธ์ต่อหลายคนนักเรียนแต่ละคนอาจมีการลงทะเบียนหลายครั้ง แต่การลงทะเบียนแต่ละครั้งเป็นของนักเรียนเพียงคนเดียว

ความสัมพันธ์แบบกลุ่มต่อกลุ่ม

ในความสัมพันธ์แบบกลุ่มต่อกลุ่มแถวในตาราง A สามารถมีแถวที่ตรงกันได้หลายแถวในตาราง B และในทางกลับกัน คุณสร้างความสัมพันธ์ดังกล่าวโดยการกำหนดตารางที่สามเรียกว่าตารางทางแยกซึ่งคีย์หลักประกอบด้วยคีย์ต่างประเทศจากทั้งตาราง A และตาราง B ตัวอย่างเช่นตารางนักเรียนและหลักสูตรมีความสัมพันธ์แบบกลุ่มต่อกลุ่มที่กำหนดโดย ความสัมพันธ์แบบหนึ่งต่อกลุ่มจากแต่ละตารางเหล่านี้ไปยังตารางการลงทะเบียน

ความสัมพันธ์แบบหนึ่งต่อหนึ่ง

ในความสัมพันธ์แบบหนึ่งต่อหนึ่งแถวในตาราง A สามารถมีแถวที่ตรงกันได้ไม่เกินหนึ่งแถวในตาราง B และในทางกลับกัน ความสัมพันธ์แบบหนึ่งต่อหนึ่งจะถูกสร้างขึ้นหากทั้งสองคอลัมน์ที่เกี่ยวข้องเป็นคีย์หลักหรือมีข้อ จำกัด เฉพาะ

ความสัมพันธ์ประเภทนี้ไม่ได้เกิดขึ้นบ่อยนักเนื่องจากข้อมูลส่วนใหญ่ที่เกี่ยวข้องในลักษณะนี้จะเป็นแบบ all-in-one table คุณอาจใช้ความสัมพันธ์แบบหนึ่งต่อกลุ่มเพื่อ -

  • แบ่งตารางที่มีหลายคอลัมน์
  • แยกส่วนของตารางด้วยเหตุผลด้านความปลอดภัย
  • จัดเก็บข้อมูลที่มีอายุการใช้งานสั้นและสามารถลบได้อย่างง่ายดายเพียงแค่ลบตาราง
  • จัดเก็บข้อมูลที่ใช้กับส่วนย่อยของตารางหลักเท่านั้น

Entity Data Model (EDM) เป็นเวอร์ชันขยายของแบบจำลองเอนทิตี - ความสัมพันธ์ซึ่งระบุรูปแบบแนวคิดของข้อมูลโดยใช้เทคนิคการสร้างแบบจำลองต่างๆ นอกจากนี้ยังหมายถึงชุดของแนวคิดที่อธิบายโครงสร้างข้อมูลโดยไม่คำนึงถึงรูปแบบที่จัดเก็บไว้

EDM สนับสนุนชุดของชนิดข้อมูลดั้งเดิมที่กำหนดคุณสมบัติในแบบจำลองแนวคิด เราจำเป็นต้องพิจารณา 3 ส่วนหลักซึ่งเป็นพื้นฐานสำหรับ Entity Framework และเรียกรวมกันว่า Entity Data Model ต่อไปนี้เป็นสามส่วนหลักของ EDM

  • รูปแบบสคีมาที่เก็บข้อมูล
  • แบบจำลองแนวคิด
  • แบบจำลองการทำแผนที่

รูปแบบสคีมาที่เก็บข้อมูล

Storage Model เรียกอีกอย่างว่า Storage Schema Definition Layer (SSDL) แสดงถึงการแสดงแผนผังของที่เก็บข้อมูลแบ็กเอนด์

แบบจำลองแนวคิด

Conceptual Model เรียกอีกอย่างว่า Conceptual Schema Definition Layer (CSDL) เป็นแบบจำลองเอนทิตีจริงซึ่งเราเขียนแบบสอบถามของเรา

แบบจำลองการทำแผนที่

Mapping Layer เป็นเพียงการแมประหว่างโมเดลแนวคิดและโมเดลที่เก็บข้อมูล

สคีมาเชิงตรรกะและการแมปกับสคีมาทางกายภาพจะแสดงเป็น EDM

  • Visual Studio ยังมี Entity Designer สำหรับการสร้างภาพของ EDM และข้อกำหนดการแม็ป

  • ผลลัพธ์ของเครื่องมือคือไฟล์ XML (* .edmx) ที่ระบุสคีมาและการแมป

  • ไฟล์ Edmx มีส่วนข้อมูลเมตาของ Entity Framework

ภาษานิยามของสคีมา

ADO.NET Entity Framework ใช้ภาษานิยามข้อมูลตาม XML ที่เรียกว่า Schema Definition Language (SDL) เพื่อกำหนด EDM Schema

  • SDL กำหนดประเภทแบบง่ายที่คล้ายกับประเภทดั้งเดิมอื่น ๆ ได้แก่ String, Int32, Double, Decimal และ DateTime เป็นต้น

  • การแจงนับซึ่งกำหนดแผนผังของค่าดั้งเดิมและชื่อถือเป็นประเภทที่เรียบง่ายเช่นกัน

  • การแจงนับได้รับการสนับสนุนจากเฟรมเวิร์กเวอร์ชัน 5.0 เป็นต้นไปเท่านั้น

  • ประเภทที่ซับซ้อนถูกสร้างขึ้นจากการรวมประเภทอื่น ๆ การรวบรวมคุณสมบัติของประเภทเหล่านี้กำหนดประเภทเอนทิตี

โมเดลข้อมูลมีแนวคิดหลักสามประการในการอธิบายโครงสร้างข้อมูล -

  • ประเภทเอนทิตี
  • ประเภทการเชื่อมโยง
  • Property

ประเภทเอนทิตี

ประเภทเอนทิตีเป็นส่วนประกอบพื้นฐานสำหรับการอธิบายโครงสร้างของข้อมูลใน EDM

  • ในแบบจำลองแนวคิดประเภทเอนทิตีถูกสร้างขึ้นจากคุณสมบัติและอธิบายโครงสร้างของแนวคิดระดับบนสุดเช่นนักเรียนและการลงทะเบียนในแอปพลิเคชันทางธุรกิจ

  • เอนทิตีแสดงถึงออบเจ็กต์เฉพาะเช่นนักเรียนหรือการลงทะเบียนเฉพาะ

  • แต่ละเอนทิตีต้องมีคีย์เอนทิตีเฉพาะภายในชุดเอนทิตี ชุดเอนทิตีคือชุดของอินสแตนซ์ของประเภทเอนทิตีเฉพาะ ชุดเอนทิตี (และชุดการเชื่อมโยง) ถูกจัดกลุ่มอย่างมีเหตุผลในคอนเทนเนอร์เอนทิตี

  • การสืบทอดได้รับการสนับสนุนกับประเภทเอนทิตีนั่นคือประเภทเอนทิตีหนึ่งสามารถได้รับมาจากอีกประเภทหนึ่ง

ประเภทการเชื่อมโยง

เป็นโครงสร้างพื้นฐานอีกอย่างหนึ่งสำหรับการอธิบายความสัมพันธ์ใน EDM ในแบบจำลองแนวความคิดการเชื่อมโยงแสดงถึงความสัมพันธ์ระหว่างเอนทิตีสองประเภทเช่นนักศึกษาและการลงทะเบียน

  • ทุกการเชื่อมโยงจะมีจุดสิ้นสุดการเชื่อมโยงสองแบบซึ่งระบุประเภทเอนทิตีที่เกี่ยวข้องในการเชื่อมโยง

  • การเชื่อมโยงแต่ละจุดสิ้นสุดยังระบุการสิ้นสุดการเชื่อมโยงหลายหลากที่ระบุจำนวนของเอนทิตีที่สามารถอยู่ที่ส่วนท้ายของการเชื่อมโยง

  • การสิ้นสุดการเชื่อมโยงหลายหลากสามารถมีค่าหนึ่ง (1) ศูนย์หรือหนึ่ง (0..1) หรือหลายค่า (*)

  • เอนทิตีที่ปลายด้านหนึ่งของการเชื่อมโยงสามารถเข้าถึงได้ผ่านคุณสมบัติการนำทางหรือผ่านคีย์ต่างประเทศหากมีการเปิดเผยในประเภทเอนทิตี

ทรัพย์สิน

ประเภทเอนทิตีประกอบด้วยคุณสมบัติที่กำหนดโครงสร้างและลักษณะ ตัวอย่างเช่นประเภทเอนทิตี Student อาจมีคุณสมบัติเช่น Student Id, Name เป็นต้น

คุณสมบัติสามารถมีข้อมูลพื้นฐาน (เช่นสตริงจำนวนเต็มหรือค่าบูลีน) หรือข้อมูลที่มีโครงสร้าง (เช่นประเภทที่ซับซ้อน)

Entity Framework ช่วยให้คุณสามารถสอบถามแทรกอัพเดตและลบข้อมูลโดยใช้อ็อบเจ็กต์ Common Language Runtime (CLR) ซึ่งเรียกว่าเอนทิตี Entity Framework จะแมปเอนทิตีและความสัมพันธ์ที่กำหนดไว้ในโมเดลของคุณกับฐานข้อมูล นอกจากนี้ยังมีสิ่งอำนวยความสะดวกให้ -

  • ทำให้ข้อมูลที่ส่งคืนจากฐานข้อมูลเป็นวัตถุเอนทิตี
  • ติดตามการเปลี่ยนแปลงที่เกิดขึ้นกับวัตถุ
  • จัดการการทำงานพร้อมกัน
  • แพร่กระจายวัตถุจะเปลี่ยนกลับไปที่ฐานข้อมูล
  • ผูกวัตถุเข้ากับตัวควบคุม

คลาสหลักที่รับผิดชอบในการโต้ตอบกับข้อมูลเป็นอ็อบเจ็กต์คือ System.Data.Entity.DbContext DbContext API ไม่ถูกนำออกใช้เป็นส่วนหนึ่งของ. NET Framework เพื่อให้มีความยืดหยุ่นและบ่อยขึ้นด้วยการเผยแพร่คุณลักษณะใหม่ ๆ ใน Code First และ DbContext API ทีม Entity Framework จะแจกจ่าย EntityFramework.dll ผ่านคุณลักษณะการแจกจ่าย NuGet ของ Microsoft

  • NuGet ช่วยให้คุณสามารถเพิ่มการอ้างอิงไปยังโครงการ. NET ของคุณได้โดยดึง DLL ที่เกี่ยวข้องไปยังโปรเจ็กต์ของคุณโดยตรงจากเว็บ

  • ส่วนขยาย Visual Studio ที่เรียกว่า Library Package Manager เป็นวิธีง่ายๆในการดึงแอสเซมบลีที่เหมาะสมจากเว็บไปยังโปรเจ็กต์ของคุณ

  • DbContext API ส่วนใหญ่มีเป้าหมายเพื่อลดความซับซ้อนของการโต้ตอบกับ Entity Framework

  • นอกจากนี้ยังลดจำนวนวิธีการและคุณสมบัติที่คุณต้องการเพื่อเข้าถึงงานที่ใช้กันทั่วไป

  • ใน Entity Framework เวอร์ชันก่อนหน้างานเหล่านี้มักจะซับซ้อนในการค้นหาและเขียนโค้ด

  • คลาสบริบทจัดการเอนทิตีอ็อบเจ็กต์ระหว่างรันไทม์ซึ่งรวมถึงการเติมอ็อบเจ็กต์ด้วยข้อมูลจากฐานข้อมูลการติดตามการเปลี่ยนแปลงและข้อมูลที่มีอยู่ไปยังฐานข้อมูล

การกำหนดคลาสที่ได้รับ DbContext

วิธีที่แนะนำในการทำงานกับบริบทคือการกำหนดคลาสที่มาจาก DbContext และแสดงคุณสมบัติ DbSet ที่แสดงถึงคอลเลกชันของเอนทิตีที่ระบุในบริบท หากคุณกำลังทำงานกับ EF Designer บริบทจะถูกสร้างขึ้นให้คุณ หากคุณกำลังทำงานกับ Code First โดยทั่วไปคุณจะเขียนบริบทด้วยตัวเอง

โค้ดต่อไปนี้เป็นตัวอย่างง่ายๆที่แสดงว่า UniContext มาจาก DbContext

  • คุณสามารถใช้คุณสมบัติอัตโนมัติกับ DbSet เช่น getter และ setter

  • นอกจากนี้ยังสร้างรหัสที่สะอาดกว่ามาก แต่คุณไม่จำเป็นต้องใช้เพื่อจุดประสงค์ในการสร้าง DbSet เมื่อคุณไม่มีตรรกะอื่นที่จะใช้

public class UniContext : DbContext {
   public UniContext() : base("UniContext") { }
   public DbSet<Student> Students { get; set; }
   public DbSet<Enrollment> Enrollments { get; set; }
   public DbSet<Course> Courses { get; set; }
}
  • ก่อนหน้านี้ EDM ใช้เพื่อสร้างคลาสบริบทที่ได้มาจากคลาส ObjectContext

  • การทำงานกับ ObjectContext มีความซับซ้อนเล็กน้อย

  • DbContext เป็น wrapper รอบ ๆ ObjectContext ซึ่งจริงๆแล้วคล้ายกับ ObjectContext และมีประโยชน์และง่ายในรูปแบบการพัฒนาทั้งหมดเช่น Code First, Model First และ Database First

แบบสอบถาม

มีคำค้นหาสามประเภทที่คุณสามารถใช้ได้เช่น -

  • การเพิ่มเอนทิตีใหม่
  • การเปลี่ยนแปลงหรืออัปเดตค่าคุณสมบัติของเอนทิตีที่มีอยู่
  • การลบเอนทิตีที่มีอยู่

การเพิ่มเอนทิตีใหม่

การเพิ่มอ็อบเจ็กต์ใหม่ด้วย Entity Framework ทำได้ง่ายเพียงแค่สร้างอินสแตนซ์ใหม่ของอ็อบเจ็กต์ของคุณและลงทะเบียนโดยใช้เมธอด Add บน DbSet รหัสต่อไปนี้ใช้สำหรับเมื่อคุณต้องการเพิ่มนักเรียนใหม่ในฐานข้อมูล

private static void AddStudent() {

   using (var context = new UniContext()) {

      var student = new Student {
         LastName = "Khan", 
         FirstMidName = "Ali", 
         EnrollmentDate = DateTime.Parse("2005-09-01") 
      };

      context.Students.Add(student); 
      context.SaveChanges();

   }
}

การเปลี่ยนเอนทิตีที่มีอยู่

การเปลี่ยนออบเจ็กต์ที่มีอยู่ทำได้ง่ายเพียงแค่อัปเดตค่าที่กำหนดให้กับคุณสมบัติที่คุณต้องการเปลี่ยนแปลงและเรียกใช้ SaveChanges ในรหัสต่อไปนี้นามสกุลของ Ali เปลี่ยนจาก Khan เป็น Aslam

private static void AddStudent() {

   private static void ChangeStudent() {

      using (var context = new UniContext()) {

         var student = (from d in context.Students
            where d.FirstMidName == "Ali" select d).Single();
         student.LastName = "Aslam";
         context.SaveChanges();

      }
   }
}

การลบเอนทิตีที่มีอยู่

ในการลบเอนทิตีโดยใช้ Entity Framework คุณใช้เมธอด Remove บน DbSet ลบงานสำหรับทั้งเอนทิตีที่มีอยู่และเพิ่มใหม่ การเรียกลบในเอนทิตีที่ถูกเพิ่ม แต่ยังไม่ได้บันทึกลงในฐานข้อมูลจะยกเลิกการเพิ่มเอนทิตี เอนทิตีจะถูกลบออกจากตัวติดตามการเปลี่ยนแปลงและไม่ถูกติดตามโดย DbContext อีกต่อไป การเรียกลบในเอนทิตีที่มีอยู่ซึ่งกำลังถูกติดตามการเปลี่ยนแปลงจะลงทะเบียนเอนทิตีสำหรับการลบในครั้งถัดไปที่เรียก SaveChanges ตัวอย่างต่อไปนี้แสดงกรณีที่นักเรียนถูกลบออกจากฐานข้อมูลที่มีชื่อแรกคือ Ali

private static void DeleteStudent() {

   using (var context = new UniContext()) {
      var bay = (from d in context.Students where d.FirstMidName == "Ali" select d).Single();
      context.Students.Remove(bay);
      context.SaveChanges();
   }
}

ใน Entity Framework มีเอนทิตีสองประเภทที่อนุญาตให้นักพัฒนาใช้คลาสข้อมูลที่กำหนดเองร่วมกับโมเดลข้อมูลโดยไม่ต้องทำการปรับเปลี่ยนคลาสข้อมูลด้วยตนเอง

  • หน่วยงาน POCO
  • พร็อกซีแบบไดนามิก

หน่วยงาน POCO

  • POCO ย่อมาจากอ็อบเจ็กต์ CLR "ธรรมดา" ซึ่งสามารถใช้เป็นอ็อบเจ็กต์โดเมนที่มีอยู่กับโมเดลข้อมูลของคุณ

  • คลาสข้อมูล POCO ที่แมปกับเอนทิตีถูกกำหนดไว้ในแบบจำลองข้อมูล

  • นอกจากนี้ยังสนับสนุนแบบสอบถามแทรกอัปเดตและลบลักษณะการทำงานส่วนใหญ่เป็นประเภทเอนทิตีที่สร้างโดยเครื่องมือตัวแบบข้อมูลเอนทิตี

  • คุณสามารถใช้เทมเพลต POCO เพื่อสร้างประเภทเอนทิตีที่คงอยู่โดยไม่รู้ตัวจากแบบจำลองแนวคิด

ลองดูตัวอย่าง Conceptual Entity Data Model ต่อไปนี้

ในการสร้างเอนทิตี POCO สำหรับโมเดลเอนทิตีด้านบน -

Step 1- คลิกขวาที่หน้าต่างนักออกแบบ จะแสดงกล่องโต้ตอบต่อไปนี้

Step 2 - เลือกรายการเพิ่มรหัสสร้าง ...

Step 3 - เลือก EF 6.x DbContext Generator เขียนชื่อจากนั้นคลิกปุ่ม Add

คุณจะเห็นในตัวสำรวจโซลูชันของคุณว่ามีการสร้างเทมเพลต POCODemo.Context.tt และ POCODemo.tt

POCODemo.Context สร้าง DbContext และชุดออบเจ็กต์ที่คุณสามารถส่งคืนและใช้สำหรับการสืบค้นพูดสำหรับบริบทนักเรียนและหลักสูตร ฯลฯ

แม่แบบอื่น ๆ เกี่ยวข้องกับประเภทนักเรียนหลักสูตรและอื่น ๆ ทั้งหมดต่อไปนี้เป็นรหัสสำหรับชั้นเรียนนักเรียนซึ่งสร้างขึ้นโดยอัตโนมัติจากแบบจำลองเอนทิตี

namespace ConsoleApplication1 {

   using System;
   using System.Collections.Generic;

   public partial class Student {

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2214:DoNotCallOverridableMethodsInConstructors")]

      public Student() {
         this.Enrollments = new HashSet<Enrollment>();
      }

      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
      public System.DateTime EnrollmentDate { get; set; }

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         CA2227:CollectionPropertiesShouldBeReadOnly")]

      public virtual ICollection<Enrollment> Enrollments { get; set; }

   }
}

ชั้นเรียนที่คล้ายกันถูกสร้างขึ้นสำหรับตารางหลักสูตรและการลงทะเบียนจากโมเดลเอนทิตี

พร็อกซีแบบไดนามิก

เมื่อสร้างอินสแตนซ์ของประเภทเอนทิตี POCO Entity Framework มักจะสร้างอินสแตนซ์ของชนิดที่ได้รับที่สร้างขึ้นแบบไดนามิกซึ่งทำหน้าที่เป็นพร็อกซีสำหรับเอนทิตี IT ยังสามารถกล่าวได้ว่าเป็นคลาสพร็อกซีรันไทม์เช่นคลาส wrapper ของเอนทิตี POCO

  • คุณสามารถแทนที่คุณสมบัติบางอย่างของเอนทิตีเพื่อดำเนินการโดยอัตโนมัติเมื่อมีการเข้าถึงคุณสมบัติ

  • กลไกนี้ใช้เพื่อสนับสนุนการโหลดความสัมพันธ์แบบเกียจคร้านและการติดตามการเปลี่ยนแปลงอัตโนมัติ

  • เทคนิคนี้ยังใช้กับโมเดลที่สร้างด้วย Code First และ EF Designer

หากคุณต้องการให้ Entity Framework รองรับการโหลดอ็อบเจ็กต์ที่เกี่ยวข้องและติดตามการเปลี่ยนแปลงในคลาส POCO คลาส POCO จะต้องเป็นไปตามข้อกำหนดต่อไปนี้ -

  • ต้องประกาศคลาสข้อมูลที่กำหนดเองด้วยการเข้าถึงแบบสาธารณะ

  • ต้องไม่ปิดผนึกคลาสข้อมูลที่กำหนดเอง

  • คลาสข้อมูลที่กำหนดเองต้องไม่เป็นนามธรรม

  • คลาสข้อมูลที่กำหนดเองต้องมีตัวสร้างสาธารณะหรือที่ได้รับการป้องกันที่ไม่มีพารามิเตอร์

  • ใช้ตัวสร้างที่ได้รับการป้องกันโดยไม่มีพารามิเตอร์หากคุณต้องการใช้เมธอด CreateObject เพื่อสร้างพร็อกซีสำหรับเอนทิตี POCO

  • การเรียกใช้เมธอด CreateObject ไม่รับประกันการสร้างพร็อกซี: คลาส POCO ต้องเป็นไปตามข้อกำหนดอื่น ๆ ที่อธิบายไว้ในหัวข้อนี้

  • คลาสไม่สามารถใช้อินเตอร์เฟส IEntityWithChangeTracker หรือ IEntityWithRelationships ได้เนื่องจากคลาสพร็อกซีใช้อินเทอร์เฟซเหล่านี้

  • ต้องตั้งค่าตัวเลือก ProxyCreationEnabled เป็น true

ตัวอย่างต่อไปนี้เป็นคลาสเอนทิตีพร็อกซีแบบไดนามิก

public partial class Course {

   public Course() {
      this.Enrollments = new HashSet<Enrollment>();
   }

   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

หากต้องการปิดใช้งานการสร้างวัตถุพร็อกซีให้ตั้งค่าคุณสมบัติ ProxyCreationEnabled เป็น false

ในฐานข้อมูลเชิงสัมพันธ์ความสัมพันธ์คือสถานการณ์ที่มีอยู่ระหว่างตารางฐานข้อมูลเชิงสัมพันธ์ผ่านคีย์ต่างประเทศ Foreign Key (FK) คือคอลัมน์หรือชุดของคอลัมน์ที่ใช้เพื่อสร้างและบังคับใช้การเชื่อมโยงระหว่างข้อมูลในสองตาราง แผนภาพต่อไปนี้ประกอบด้วยสามตาราง

  • Student
  • Course
  • Enrollment

ในแผนภาพด้านบนคุณสามารถเห็นการเชื่อมโยง / ความสัมพันธ์ระหว่างตาราง มีความสัมพันธ์สามประเภทระหว่างตารางและความสัมพันธ์ระหว่างตารางต่างๆขึ้นอยู่กับวิธีกำหนดคอลัมน์ที่เกี่ยวข้อง

  • ความสัมพันธ์แบบหนึ่งต่อกลุ่ม
  • ความสัมพันธ์แบบกลุ่มต่อกลุ่ม
  • ความสัมพันธ์แบบหนึ่งต่อหนึ่ง

ความสัมพันธ์แบบหนึ่งต่อกลุ่ม

  • ความสัมพันธ์แบบหนึ่งต่อกลุ่มเป็นประเภทของความสัมพันธ์ที่พบบ่อยที่สุด

  • ในความสัมพันธ์ประเภทนี้แถวในตาราง A สามารถมีแถวที่ตรงกันได้หลายแถวในตาราง B แต่แถวในตาราง B สามารถมีแถวที่ตรงกันเพียงแถวเดียวในตาราง A

  • คีย์ต่างประเทศถูกกำหนดไว้ในตารางที่แสดงถึงจุดสิ้นสุดของความสัมพันธ์

  • ตัวอย่างเช่นในแผนภาพด้านบนตารางนักเรียนและการลงทะเบียนมีความสัมพันธ์แบบเดียวกันนักเรียนแต่ละคนอาจมีการลงทะเบียนหลายครั้ง แต่การลงทะเบียนแต่ละครั้งเป็นของนักเรียนเพียงคนเดียว

ในกรอบงานเอนทิตีสามารถสร้างความสัมพันธ์เหล่านี้ด้วยรหัสได้เช่นกัน ต่อไปนี้เป็นตัวอย่างของชั้นเรียนนักเรียนและการลงทะเบียนที่เชื่อมโยงกับความสัมพันธ์แบบหนึ่งต่อหลาย

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

ในโค้ดด้านบนคุณจะเห็นว่าคลาสนักเรียนมีคอลเล็กชันการลงทะเบียน แต่คลาสการลงทะเบียนมี Student Object เดียว

ความสัมพันธ์แบบกลุ่มต่อกลุ่ม

ในความสัมพันธ์แบบกลุ่มต่อกลุ่มแถวในตาราง A สามารถมีแถวที่ตรงกันได้หลายแถวในตาราง B และในทางกลับกัน

  • คุณสามารถสร้างความสัมพันธ์ดังกล่าวได้โดยการกำหนดตารางที่สามเรียกว่าตารางทางแยกซึ่งคีย์หลักประกอบด้วยคีย์ต่างประเทศจากทั้งตาราง A และตาราง B

  • ตัวอย่างเช่นตารางนักเรียนและหลักสูตรมีความสัมพันธ์แบบกลุ่มต่อกลุ่มที่กำหนดโดยความสัมพันธ์แบบหนึ่งต่อกลุ่มจากแต่ละตารางเหล่านี้ไปยังตารางการลงทะเบียน

รหัสต่อไปนี้ประกอบด้วยชั้นเรียนหลักสูตรและสองชั้นเรียนข้างต้นกล่าวคือ Student และ Enrollment.

public class Course {
   [DatabaseGenerated(DatabaseGeneratedOption.None)]
	
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   public int Credits { get; set; } 
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

คุณจะเห็นได้ว่าทั้งคลาสหลักสูตรและคลาสนักเรียนมีคอลเล็กชันของอ็อบเจ็กต์การลงทะเบียนซึ่งสร้างความสัมพันธ์แบบกลุ่มต่อกลุ่มผ่านการลงทะเบียนคลาสทางแยก

ความสัมพันธ์แบบหนึ่งต่อหนึ่ง

  • ในความสัมพันธ์แบบหนึ่งต่อหนึ่งแถวในตาราง A สามารถมีแถวที่ตรงกันได้ไม่เกินหนึ่งแถวในตาราง B และในทางกลับกัน

  • ความสัมพันธ์แบบหนึ่งต่อหนึ่งจะถูกสร้างขึ้นหากทั้งสองคอลัมน์ที่เกี่ยวข้องเป็นคีย์หลักหรือมีข้อ จำกัด เฉพาะ

  • ในความสัมพันธ์แบบหนึ่งต่อกลุ่มคีย์หลักจะทำหน้าที่เป็นคีย์ต่างประเทศเพิ่มเติมและไม่มีคอลัมน์คีย์ต่างประเทศแยกสำหรับตารางใดตารางหนึ่ง

ความสัมพันธ์ประเภทนี้ไม่เกิดขึ้นบ่อยนักเนื่องจากข้อมูลส่วนใหญ่ที่เกี่ยวข้องในลักษณะนี้จะรวมอยู่ในตารางเดียว คุณอาจใช้ความสัมพันธ์แบบหนึ่งต่อกลุ่มเพื่อ -

  • แบ่งตารางที่มีหลายคอลัมน์
  • แยกส่วนของตารางด้วยเหตุผลด้านความปลอดภัย
  • จัดเก็บข้อมูลที่มีอายุการใช้งานสั้นและสามารถลบได้อย่างง่ายดายเพียงแค่ลบตาราง
  • จัดเก็บข้อมูลที่ใช้กับส่วนย่อยของตารางหลักเท่านั้น

รหัสต่อไปนี้คือการเพิ่มชื่อคลาส StudentProfile อื่นซึ่งมีรหัสอีเมลและรหัสผ่านของนักเรียน

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 virtual StudentProfile StudentProfile { get; set; }
}

public class StudentProfile {

   public StudentProfile() {}
   public int ID { get; set; }
   public string Email { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

คุณสามารถดูได้ว่าคลาสเอนทิตี Student มีคุณสมบัติการนำทาง StudentProfile และ StudentProfile มีคุณสมบัติการนำทางของนักเรียน

นักเรียนแต่ละคนมีอีเมลและรหัสผ่านเพียงชุดเดียวเพื่อเข้าสู่ระบบในโดเมนของมหาวิทยาลัย ข้อมูลเหล่านี้สามารถเพิ่มลงในตารางนักเรียนได้ แต่เพื่อความปลอดภัยจะถูกแยกไปยังตารางอื่น

อายุการใช้งาน

อายุการใช้งานของบริบทเริ่มต้นเมื่ออินสแตนซ์ถูกสร้างขึ้นและสิ้นสุดลงเมื่ออินสแตนซ์ถูกกำจัดหรือรวบรวมขยะ

  • อายุการใช้งานตามบริบทเป็นการตัดสินใจที่สำคัญมากเมื่อเราใช้ ORM

  • บริบททำงานเหมือนเอนทิตีแคชดังนั้นจึงหมายถึงมีการอ้างอิงถึงเอนทิตีที่โหลดทั้งหมดซึ่งอาจเติบโตเร็วมากในการใช้หน่วยความจำและยังทำให้หน่วยความจำรั่วไหล

  • ในแผนภาพด้านล่างคุณสามารถดูระดับบนของเวิร์กโฟลว์ข้อมูลจากแอปพลิเคชันไปยังฐานข้อมูลผ่านทางบริบทและในทางกลับกัน

วงจรชีวิตของเอนทิตี

Entity Lifecycle อธิบายกระบวนการที่เอนทิตีถูกสร้างเพิ่มแก้ไขลบ ฯลฯ เอนทิตีมีหลายสถานะในช่วงอายุการใช้งาน ก่อนที่จะดูวิธีการดึงสถานะเอนทิตีมาดูกันว่าสถานะเอนทิตีคืออะไร สถานะเป็น enum ประเภทSystem.Data.EntityState ที่ประกาศค่าต่อไปนี้ -

  • Added: นิติบุคคลถูกทำเครื่องหมายว่าเพิ่มแล้ว

  • Deleted: นิติบุคคลถูกทำเครื่องหมายว่าลบแล้ว

  • Modified: มีการแก้ไขเอนทิตี

  • Unchanged: ไม่ได้แก้ไขเอนทิตี

  • Detached: ไม่ได้ติดตามเอนทิตี

การเปลี่ยนแปลงสถานะในวงจรชีวิตของเอนทิตี

บางครั้งสถานะของเอนทิตีจะถูกกำหนดโดยบริบทโดยอัตโนมัติ แต่นักพัฒนายังสามารถแก้ไขได้ด้วยตนเอง แม้ว่าการรวมกันทั้งหมดของสวิตช์จากสถานะหนึ่งไปยังอีกสถานะหนึ่งจะเป็นไปได้ แต่บางส่วนก็ไม่มีความหมาย ตัวอย่างเช่น,Added นิติบุคคลของ Deleted รัฐหรือในทางกลับกัน

ขอหารือเกี่ยวกับสถานะต่างๆ

สถานะไม่เปลี่ยนแปลง

  • เมื่อเอนทิตีไม่มีการเปลี่ยนแปลงจะถูกผูกไว้กับบริบท แต่ไม่ได้รับการแก้ไข

  • โดยค่าเริ่มต้นเอนทิตีที่ดึงมาจากฐานข้อมูลจะอยู่ในสถานะนี้

  • เมื่อเอนทิตีแนบกับบริบท (ด้วยวิธีการแนบ) เอนทิตีจะอยู่ในสถานะไม่เปลี่ยนแปลงในทำนองเดียวกัน

  • บริบทไม่สามารถติดตามการเปลี่ยนแปลงของออบเจ็กต์ที่ไม่ได้อ้างอิงดังนั้นเมื่อแนบมาแล้วจะถือว่าไม่มีการเปลี่ยนแปลง

สถานะแยก

  • แยกออกเป็นสถานะเริ่มต้นของเอนทิตีที่สร้างขึ้นใหม่เนื่องจากบริบทไม่สามารถติดตามการสร้างวัตถุใด ๆ ในโค้ดของคุณ

  • สิ่งนี้เป็นจริงแม้ว่าคุณจะสร้างอินสแตนซ์เอนทิตีภายในบล็อกโดยใช้บริบท

  • แยกออกแม้กระทั่งสถานะของเอนทิตีที่ดึงมาจากฐานข้อมูลเมื่อปิดใช้งานการติดตาม

  • เมื่อเอนทิตีถูกแยกออกจะไม่ถูกผูกไว้กับบริบทดังนั้นสถานะจึงไม่ถูกติดตาม

  • สามารถกำจัดแก้ไขใช้ร่วมกับคลาสอื่น ๆ หรือใช้ในลักษณะอื่นที่คุณอาจต้องการ

  • เนื่องจากไม่มีการติดตามบริบทจึงไม่มีความหมายกับ Entity Framework

เพิ่มรัฐ

  • เมื่อเอนทิตีอยู่ในสถานะเพิ่มคุณมีตัวเลือกน้อย ในความเป็นจริงคุณสามารถแยกออกจากบริบทเท่านั้น

  • โดยปกติแล้วแม้ว่าคุณจะปรับเปลี่ยนคุณสมบัติบางอย่างสถานะจะยังคงถูกเพิ่มเนื่องจากการย้ายไปที่ Modified, Unchanged หรือ Deleted นั้นไม่มีเหตุผล

  • เป็นเอนทิตีใหม่และไม่มีความสอดคล้องกับแถวในฐานข้อมูล

  • นี่เป็นข้อกำหนดเบื้องต้นพื้นฐานสำหรับการอยู่ในสถานะใดสถานะหนึ่ง (แต่บริบทนี้ไม่ได้บังคับใช้)

สถานะที่แก้ไข

  • เมื่อเอนทิตีถูกแก้ไขนั่นหมายความว่าอยู่ในสถานะไม่เปลี่ยนแปลงจากนั้นคุณสมบัติบางอย่างก็เปลี่ยนไป

  • หลังจากที่เอนทิตีเข้าสู่สถานะ Modified เอนทิตีสามารถย้ายไปยังสถานะ Detached หรือ Deleted ได้ แต่จะไม่สามารถย้อนกลับไปยังสถานะไม่เปลี่ยนแปลงแม้ว่าคุณจะกู้คืนค่าดั้งเดิมด้วยตนเองก็ตาม

  • ไม่สามารถเปลี่ยนเป็นเพิ่มได้เว้นแต่คุณจะแยกและเพิ่มเอนทิตีลงในบริบทเนื่องจากมีแถวที่มี ID นี้อยู่แล้วในฐานข้อมูลและคุณจะได้รับข้อยกเว้นรันไทม์เมื่อยังคงมีอยู่

สถานะที่ถูกลบ

  • เอนทิตีเข้าสู่สถานะที่ถูกลบเนื่องจากไม่มีการเปลี่ยนแปลงหรือแก้ไขจากนั้นจึงใช้เมธอด DeleteObject

  • นี่เป็นสถานะที่ จำกัด มากที่สุดเนื่องจากไม่มีจุดหมายเปลี่ยนจากสถานะนี้เป็นค่าอื่น แต่แยกออก

usingคำสั่งหากคุณต้องการให้ทรัพยากรทั้งหมดที่บริบทควบคุมถูกกำจัดเมื่อสิ้นสุดบล็อก เมื่อคุณใช้using จากนั้นคอมไพเลอร์จะสร้าง try / ปิดกั้นโดยอัตโนมัติและเรียกว่า dispose ในบล็อกสุดท้าย

using (var context = new UniContext()) {

   var student = new Student {
      LastName = "Khan", 
      FirstMidName = "Ali", 
      EnrollmentDate = DateTime.Parse("2005-09-01")
   };

   context.Students.Add(student);
   context.SaveChanges();
}

เมื่อทำงานกับบริบทที่ใช้งานมายาวนานให้พิจารณาสิ่งต่อไปนี้ -

  • เมื่อคุณโหลดอ็อบเจ็กต์และการอ้างอิงลงในหน่วยความจำมากขึ้นการใช้หน่วยความจำของบริบทอาจเพิ่มขึ้นอย่างรวดเร็ว ซึ่งอาจทำให้เกิดปัญหาด้านประสิทธิภาพ

  • อย่าลืมทิ้งบริบทเมื่อไม่จำเป็นต้องใช้อีกต่อไป

  • หากข้อยกเว้นทำให้บริบทอยู่ในสถานะที่ไม่สามารถกู้คืนได้แอปพลิเคชันทั้งหมดอาจยุติลง

  • โอกาสที่จะพบปัญหาที่เกี่ยวข้องกับภาวะพร้อมกันจะเพิ่มขึ้นเมื่อช่องว่างระหว่างเวลาที่ข้อมูลถูกสอบถามและอัปเดตเพิ่มขึ้น

  • เมื่อทำงานกับเว็บแอปพลิเคชันให้ใช้อินสแตนซ์บริบทต่อคำขอ

  • เมื่อทำงานกับ Windows Presentation Foundation (WPF) หรือ Windows Forms ให้ใช้อินสแตนซ์บริบทต่อฟอร์ม ซึ่งช่วยให้คุณใช้ฟังก์ชันการติดตามการเปลี่ยนแปลงที่บริบทมีให้

กฎของ Thumb

Web Applications

  • ตอนนี้ถือเป็นแนวทางปฏิบัติทั่วไปและเป็นแนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้งานเว็บบริบทจะถูกใช้ต่อคำขอ

  • ในเว็บแอปพลิเคชันเราจัดการกับคำขอที่สั้นมาก แต่มีธุรกรรมเซิร์ฟเวอร์ทั้งหมดดังนั้นจึงเป็นระยะเวลาที่เหมาะสมสำหรับบริบทที่จะดำเนินการ

Desktop Applications

  • สำหรับแอปพลิเคชันเดสก์ท็อปเช่น Win Forms / WPF เป็นต้นบริบทจะถูกใช้ต่อแบบฟอร์ม / โต้ตอบ / เพจ

  • เนื่องจากเราไม่ต้องการให้บริบทเป็นซิงเกิลตันสำหรับแอปพลิเคชันของเราเราจะกำจัดทิ้งเมื่อเราย้ายจากรูปแบบหนึ่งไปยังอีกรูปแบบหนึ่ง

  • ด้วยวิธีนี้เราจะได้รับความสามารถมากมายของบริบทและจะไม่ต้องทนทุกข์ทรมานจากผลกระทบของบริบทที่ใช้งานมายาวนาน

Entity Framework มีสามแนวทางในการสร้างแบบจำลองเอนทิตีและแต่ละวิธีมีข้อดีและข้อเสียของตนเอง

  • รหัสแรก
  • ฐานข้อมูลก่อน
  • รุ่นแรก

ในบทนี้เราจะอธิบายสั้น ๆ เกี่ยวกับแนวทางแรกของรหัส นักพัฒนาบางคนชอบที่จะทำงานร่วมกับ Designer ใน Code ในขณะที่บางคนต้องการทำงานกับ Code ของตนเท่านั้น สำหรับนักพัฒนาเหล่านั้น Entity Framework มีเวิร์กโฟลว์การสร้างแบบจำลองที่เรียกว่า Code First

  • เวิร์กโฟลว์การสร้างโมเดล Code First กำหนดเป้าหมายฐานข้อมูลที่ไม่มีอยู่และ Code First จะสร้างขึ้น

  • นอกจากนี้ยังสามารถใช้หากคุณมีฐานข้อมูลว่างจากนั้น Code First จะเพิ่มตารางใหม่ด้วย

  • Code First ช่วยให้คุณกำหนดโมเดลของคุณโดยใช้คลาส C # หรือ VB.Net

  • การกำหนดค่าเพิ่มเติมสามารถเลือกดำเนินการได้โดยใช้แอตทริบิวต์ในคลาสและคุณสมบัติของคุณหรือใช้ API ที่คล่องแคล่ว

ทำไมต้องเป็นรหัสแรก

  • Code First สร้างขึ้นจากชุดตัวต่อ อันดับแรกคือคลาสโดเมนของคุณ

  • คลาสโดเมนไม่มีส่วนเกี่ยวข้องกับ Entity Framework เป็นเพียงรายการในโดเมนธุรกิจของคุณ

  • ดังนั้น Entity Framework จะมีบริบทที่จัดการปฏิสัมพันธ์ระหว่างคลาสเหล่านั้นกับฐานข้อมูลของคุณ

  • บริบทไม่เฉพาะเจาะจงสำหรับ Code First เป็นคุณสมบัติของ Entity Framework

  • Code First เพิ่มตัวสร้างโมเดลที่ตรวจสอบคลาสของคุณว่าบริบทกำลังจัดการจากนั้นใช้ชุดของกฎหรืออนุสัญญาเพื่อกำหนดว่าคลาสเหล่านั้นและความสัมพันธ์อธิบายโมเดลอย่างไรและโมเดลนั้นควรแมปกับฐานข้อมูลของคุณอย่างไร

  • ทั้งหมดนี้เกิดขึ้นที่รันไทม์ คุณจะไม่เห็นโมเดลนี้ แต่อยู่ในความทรงจำ

  • Code First มีความสามารถในการใช้โมเดลนั้นเพื่อสร้างฐานข้อมูลหากต้องการ

  • นอกจากนี้ยังสามารถอัปเดตฐานข้อมูลหากโมเดลเปลี่ยนแปลงโดยใช้คุณลักษณะที่เรียกว่า Code First Migrations

ในบทนี้ให้เราเรียนรู้วิธีการสร้างโมเดลข้อมูลเอนทิตีในตัวออกแบบโดยใช้เวิร์กโฟลว์ที่เรียกว่า Model First

  • Model First เหมาะอย่างยิ่งสำหรับเมื่อคุณเริ่มโครงการใหม่ที่ยังไม่มีฐานข้อมูล

  • โมเดลถูกเก็บไว้ในไฟล์ EDMX และสามารถดูและแก้ไขได้ใน Entity Framework Designer

  • ใน Model First คุณกำหนดโมเดลของคุณในตัวออกแบบ Entity Framework จากนั้นสร้าง SQL ซึ่งจะสร้างสคีมาฐานข้อมูลให้ตรงกับโมเดลของคุณจากนั้นคุณดำเนินการ SQL เพื่อสร้างสคีมาในฐานข้อมูลของคุณ

  • คลาสที่คุณโต้ตอบด้วยในแอปพลิเคชันของคุณจะสร้างขึ้นโดยอัตโนมัติจากไฟล์ EDMX

ต่อไปนี้เป็นตัวอย่างง่ายๆของการสร้างโครงการคอนโซลใหม่โดยใช้แนวทาง Model First

Step 1 - เปิด Visual Studio แล้วเลือก File → New → Project

Step 2 - เลือกติดตั้ง→เทมเพลต→ Visual C # → Windows จากบานหน้าต่างด้านซ้ายจากนั้นในบานหน้าต่างตรงกลางให้เลือกแอปพลิเคชันคอนโซล

Step 3 - ป้อน EFModelFirstDemo ในฟิลด์ชื่อ

Step 4 - ในการสร้างโมเดลให้คลิกขวาที่โปรเจ็กต์คอนโซลของคุณก่อนในตัวสำรวจโซลูชันแล้วเลือกเพิ่ม→รายการใหม่ ...

กล่องโต้ตอบต่อไปนี้จะเปิดขึ้น

Step 5 - เลือก ADO.NET Entity Data Model จากบานหน้าต่างตรงกลางและป้อนชื่อ ModelFirstDemoDB ในฟิลด์ Name

Step 6 - คลิกปุ่มเพิ่มซึ่งจะเปิดกล่องโต้ตอบตัวช่วยสร้างโมเดลข้อมูลเอนทิตี

Step 7- เลือก Empty EF Designer model แล้วคลิกปุ่ม Next Entity Framework Designer จะเปิดขึ้นด้วยโมเดลเปล่า ตอนนี้เราสามารถเริ่มเพิ่มเอนทิตีคุณสมบัติและการเชื่อมโยงให้กับโมเดลได้

Step 8- คลิกขวาบนพื้นผิวการออกแบบและเลือกคุณสมบัติ ในหน้าต่างคุณสมบัติเปลี่ยนชื่อคอนเทนเนอร์เอนทิตีเป็น ModelFirstDemoDBContext

Step 9 - คลิกขวาที่พื้นผิวการออกแบบแล้วเลือกเพิ่มใหม่→เอนทิตี ...

กล่องโต้ตอบเพิ่มเอนทิตีจะเปิดขึ้นดังที่แสดงในภาพต่อไปนี้

Step 10 - ป้อน Student เป็นชื่อนิติบุคคลและ Student Id เป็นชื่อคุณสมบัติแล้วคลิก Ok

Step 11 - คลิกขวาที่เอนทิตีใหม่บนพื้นผิวการออกแบบและเลือกเพิ่มใหม่→คุณสมบัติสเกลาร์ป้อนชื่อเป็นชื่อของคุณสมบัติ

Step 12 - ป้อน FirstName จากนั้นเพิ่มคุณสมบัติสเกลาร์อีกสองคุณสมบัติเช่น LastName และ EnrollmentDate

Step 13 - เพิ่มหลักสูตรเอนทิตีและการลงทะเบียนอีกสองรายการโดยทำตามขั้นตอนทั้งหมดที่กล่าวข้างต้นและเพิ่มคุณสมบัติสเกลาร์ตามที่แสดงในขั้นตอนต่อไปนี้

Step 14 - เรามีสามเอนทิตีใน Visual Designer มาเพิ่มการเชื่อมโยงหรือความสัมพันธ์ระหว่างกัน

Step 15 - คลิกขวาที่พื้นผิวการออกแบบแล้วเลือกเพิ่มใหม่→การเชื่อมโยง ...

Step 16 - ทำให้ปลายด้านหนึ่งของความสัมพันธ์ชี้ไปที่นักเรียนด้วยความหลายหลากของหนึ่งและอีกจุดสิ้นสุดไปที่การลงทะเบียนที่มีหลายหลากของจำนวนมาก

Step 17 - หมายความว่านักเรียนมีการลงทะเบียนและการลงทะเบียนจำนวนมากเป็นของนักเรียนหนึ่งคน

Step 18 - ตรวจสอบให้แน่ใจว่าได้เลือกช่องเพิ่มคุณสมบัติคีย์ต่างประเทศในเอนทิตี 'โพสต์' แล้วคลิกตกลง

Step 19 - ในทำนองเดียวกันให้เพิ่มความสัมพันธ์ระหว่างหลักสูตรและการลงทะเบียนอีกหนึ่งรายการ

Step 20 - โมเดลข้อมูลของคุณจะมีลักษณะเหมือนหน้าจอต่อไปนี้หลังจากเพิ่มการเชื่อมโยงระหว่างเอนทิตี

ตอนนี้เรามีโมเดลง่ายๆที่เราสามารถสร้างฐานข้อมูลและใช้ในการอ่านและเขียนข้อมูลได้ มาสร้างฐานข้อมูลกันเลย

Step 1 - คลิกขวาที่พื้นผิวการออกแบบและเลือกสร้างฐานข้อมูลจากแบบจำลอง ...

Step 2 - คุณสามารถเลือกฐานข้อมูลที่มีอยู่หรือสร้างการเชื่อมต่อใหม่โดยคลิกที่การเชื่อมต่อใหม่ ...

Step 3 - ในการสร้างฐานข้อมูลใหม่ให้คลิกที่การเชื่อมต่อใหม่ ...

Step 4 - ป้อนชื่อเซิร์ฟเวอร์และชื่อฐานข้อมูล

Step 5 - คลิกถัดไป

Step 6- คลิกเสร็จสิ้น สิ่งนี้จะเพิ่มไฟล์ * .edmx.sql ในโปรเจ็กต์ คุณสามารถรันสคริปต์ DDL ใน Visual Studio ได้โดยเปิดไฟล์. sql จากนั้นคลิกขวาและเลือก Execute

Step 7 - กล่องโต้ตอบต่อไปนี้จะปรากฏขึ้นเพื่อเชื่อมต่อกับฐานข้อมูล

Step 8 - เมื่อดำเนินการสำเร็จคุณจะเห็นข้อความต่อไปนี้

Step 9 - ไปที่ server explorer คุณจะเห็นว่าฐานข้อมูลถูกสร้างขึ้นด้วยตารางสามตารางที่ระบุไว้

ต่อไปเราต้องสลับโมเดลของเราเพื่อสร้างโค้ดที่ใช้ DbContext API

Step 1 - คลิกขวาที่จุดว่างของโมเดลของคุณใน EF Designer แล้วเลือก Add Code Generation Item ...

คุณจะเห็นว่ากล่องโต้ตอบเพิ่มรายการใหม่ต่อไปนี้เปิดขึ้น

Step 2 - เลือก EF 6.x DbContext Generator ในบานหน้าต่างตรงกลางและป้อน ModelFirstDemoModel ในฟิลด์ Name

Step 3 - คุณจะเห็นในตัวสำรวจโซลูชันของคุณว่าเทมเพลต ModelFirstDemoModel.Context.tt และ ModelFirstDemoModel.tt ถูกสร้างขึ้น

ModelFirstDemoModel.Context สร้าง DbCcontext และชุดออบเจ็กต์ที่คุณสามารถส่งคืนและใช้สำหรับการสอบถามพูดสำหรับบริบทนักเรียนและหลักสูตรเป็นต้น

แม่แบบอื่น ๆ เกี่ยวข้องกับทุกประเภทนักเรียนหลักสูตรและอื่น ๆ ต่อไปนี้คือชั้นเรียนนักเรียนซึ่งสร้างขึ้นโดยอัตโนมัติจากแบบจำลองเอนทิตี

ต่อไปนี้เป็นรหัส C # ซึ่งข้อมูลบางส่วนจะถูกป้อนและดึงมาจากฐานข้อมูล

using System;
using System.Linq;

namespace EFModelFirstDemo {

   class Program {

      static void Main(string[] args) {

         using (var db = new ModelFirstDemoDBContext()) {

            // Create and save a new Student

            Console.Write("Enter a name for a new Student: ");
            var firstName = Console.ReadLine();

            var student = new Student {
               StudentID = 1,
               FirstName = firstName
            };
				
            db.Students.Add(student);
            db.SaveChanges();
				
            var query = from b in db.Students
               orderby b.FirstName select b;

            Console.WriteLine("All student in the database:");

            foreach (var item in query) {
               Console.WriteLine(item.FirstName);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
         }
      }
   }
}

เมื่อดำเนินการโค้ดด้านบนคุณจะได้รับผลลัพธ์ต่อไปนี้ -

Enter a name for a new Student:
Ali Khan
All student in the database:
Ali Khan
Press any key to exit...

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ในบทนี้ให้เราเรียนรู้เกี่ยวกับการสร้างแบบจำลองข้อมูลเอนทิตีด้วยวิธี Database First

  • แนวทางแรกของฐานข้อมูลเป็นทางเลือกสำหรับแนวทางของ Code First และ Model First สำหรับโมเดลข้อมูลเอนทิตี สร้างรหัสโมเดล (คลาสคุณสมบัติ DbContext ฯลฯ ) จากฐานข้อมูลในโครงการและคลาสเหล่านั้นจะกลายเป็นลิงก์ระหว่างฐานข้อมูลและคอนโทรลเลอร์

  • Database First Approach สร้างกรอบเอนทิตีจากฐานข้อมูลที่มีอยู่ เราใช้ฟังก์ชันอื่น ๆ ทั้งหมดเช่นการซิงค์โมเดล / ฐานข้อมูลและการสร้างรหัสในลักษณะเดียวกับที่เราใช้ในแนวทาง Model First

ลองยกตัวอย่างง่ายๆ เรามีฐานข้อมูลอยู่แล้วซึ่งมี 3 ตารางดังที่แสดงในภาพต่อไปนี้

Step 1 - มาสร้างโปรเจ็กต์คอนโซลใหม่ด้วยชื่อ DatabaseFirstDemo

Step 2 - ในการสร้างโมเดลให้คลิกขวาที่โปรเจ็กต์คอนโซลของคุณในตัวสำรวจโซลูชันก่อนแล้วเลือกเพิ่ม→รายการใหม่ ...

Step 3 - เลือก ADO.NET Entity Data Model จากบานหน้าต่างตรงกลางและป้อนชื่อ DatabaseFirstModel ในฟิลด์ Name

Step 4 - คลิกปุ่มเพิ่มซึ่งจะเปิดกล่องโต้ตอบตัวช่วยสร้างโมเดลข้อมูลเอนทิตี

Step 5 - เลือก EF Designer จากฐานข้อมูลและคลิกปุ่มถัดไป

Step 6 - เลือกฐานข้อมูลที่มีอยู่แล้วคลิกถัดไป

Step 7 - เลือก Entity Framework 6.x แล้วคลิกถัดไป

Step 8 - เลือกตารางทั้งหมดมุมมองและขั้นตอนการจัดเก็บที่คุณต้องการรวมแล้วคลิกเสร็จสิ้น

คุณจะเห็นว่าโมเดลเอนทิตีและคลาส POCO ถูกสร้างขึ้นจากฐานข้อมูล

ตอนนี้ให้เราดึงนักเรียนทั้งหมดจากฐานข้อมูลโดยเขียนรหัสต่อไปนี้ในไฟล์ program.cs

using System;
using System.Linq;

namespace DatabaseFirstDemo {

   class Program {

      static void Main(string[] args) {

         using (var db = new UniContextEntities()) {

            var query = from b in db.Students
               orderby b.FirstMidName select b;

            Console.WriteLine("All All student in the database:");

            foreach (var item in query) {
               Console.WriteLine(item.FirstMidName +" "+ item.LastName);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
         }
      }
   }
}

เมื่อโปรแกรมข้างต้นทำงานคุณจะได้รับผลลัพธ์ต่อไปนี้ -

All student in the database:
Ali Khan
Arturo   finand
Bill Gates
Carson Alexander
Gytis Barzdukas
Laura Norman
Meredith Alonso
Nino Olivetto
Peggy Justice
Yan Li
Press any key to exit...

เมื่อโปรแกรมด้านบนถูกเรียกใช้งานคุณจะเห็นชื่อนักเรียนทั้งหมดที่เคยกรอกไว้ในฐานข้อมูล

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ในบทนี้ให้เรามุ่งเน้นไปที่การสร้างโมเดลด้วย Designer หรือ Database First หรือเพียงแค่ใช้ Code First ต่อไปนี้เป็นแนวทางบางประการที่จะช่วยให้คุณตัดสินใจเลือกเวิร์กโฟลว์การสร้างแบบจำลอง

  • เราได้เห็นตัวอย่างของ Code First modeling, Database First modeling และ Model First modeling workflow ไปแล้ว

  • เวิร์กโฟลว์ Database First และ Model First ใช้ Designer แต่อย่างใดอย่างหนึ่งเริ่มต้นด้วยฐานข้อมูลเพื่อสร้างโมเดลและอีกขั้นเริ่มต้นที่โมเดลเพื่อสร้างฐานข้อมูล

  • สำหรับนักพัฒนาที่ไม่ต้องการใช้ Visual Designer บวกกับการสร้างโค้ด Entity Framework มีเวิร์กโฟลว์ที่แตกต่างไปจากเดิมอย่างสิ้นเชิงที่เรียกว่า Code First

  • เวิร์กโฟลว์ทั่วไปสำหรับ Code First นั้นยอดเยี่ยมสำหรับแอปพลิเคชันใหม่ล่าสุดที่คุณไม่มีฐานข้อมูล คุณกำหนดคลาสและโค้ดของคุณจากนั้นให้ Code First พิจารณาว่าฐานข้อมูลของคุณควรมีลักษณะอย่างไร

  • นอกจากนี้ยังเป็นไปได้ที่จะเริ่ม Code First ด้วยฐานข้อมูลและนั่นทำให้ Code First มีความขัดแย้งเล็กน้อย แต่มีเครื่องมือที่ช่วยให้คุณทำวิศวกรรมย้อนกลับฐานข้อมูลเป็นชั้นเรียนซึ่งเป็นวิธีที่ดีในการเริ่มต้นการเขียนโค้ด

เมื่อได้รับตัวเลือกเหล่านี้มาดูที่แผนผังการตัดสินใจ

  • หากคุณต้องการทำงานกับ Visual Designer ในโค้ดที่สร้างขึ้นคุณจะต้องเลือกหนึ่งในเวิร์กโฟลว์ที่เกี่ยวข้องกับ EF Designer หากฐานข้อมูลของคุณมีอยู่แล้ว Database First คือเส้นทางของคุณ

  • หากคุณต้องการใช้ Visual Designer ในโครงการใหม่ที่ไม่มีฐานข้อมูลคุณจะต้องใช้ Model First

  • หากคุณแค่ต้องการทำงานกับโค้ดไม่ใช่นักออกแบบ Code First ก็น่าจะเหมาะกับคุณพร้อมกับตัวเลือกในการใช้เครื่องมือที่ย้อนวิศวกรฐานข้อมูลไปยังคลาส

  • หากคุณมีคลาสอยู่แล้วทางออกที่ดีที่สุดคือใช้กับ Code First

ในบทก่อนหน้านี้คุณได้เรียนรู้วิธีการกำหนดโมเดลข้อมูลเอนทิตีที่แตกต่างกันสามวิธี

  • สองในนั้นคือ Database First และ Model First ขึ้นอยู่กับตัวออกแบบ Entity Framework รวมกับการสร้างโค้ด

  • ประการที่สาม Code First ช่วยให้คุณสามารถข้ามนักออกแบบภาพและเขียนโค้ดของคุณเองได้

  • ไม่ว่าคุณจะเลือกเส้นทางใดคุณจะได้รับคลาสโดเมนและคลาสเอนทิตีเฟรมเวิร์ก DbContext อย่างน้อยหนึ่งคลาสช่วยให้คุณสามารถดึงและเก็บรักษาข้อมูลที่เกี่ยวข้องกับคลาสเหล่านั้นได้

DbContext API ในแอปพลิเคชันของคุณใช้เป็นสะพานเชื่อมระหว่างคลาสและฐานข้อมูลของคุณ DbContext เป็นหนึ่งในคลาสที่สำคัญที่สุดใน Entity Framework

  • ช่วยให้สามารถแสดงและดำเนินการสืบค้น

  • ใช้ผลลัพธ์แบบสอบถามจากฐานข้อมูลและแปลงเป็นอินสแตนซ์ของคลาสโมเดลของเรา

  • สามารถติดตามการเปลี่ยนแปลงของเอนทิตีรวมถึงการเพิ่มและการลบจากนั้นทริกเกอร์การสร้างคำสั่งแทรกอัปเดตและลบที่ส่งไปยังฐานข้อมูลตามต้องการ

ต่อไปนี้เป็นคลาสบริบทโฆษณาโดเมนที่เราจะดำเนินการต่างๆในบทนี้ นี่เป็นตัวอย่างเดียวกับที่เราได้สร้างขึ้นในฐานข้อมูลแนวทางแรก

การปรับใช้คลาสบริบท

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Core.Objects;
using System.Linq;

namespace DatabaseFirstDemo {

   public partial class UniContextEntities : DbContext {

      public UniContextEntities(): base("name = UniContextEntities") {}

      protected override void OnModelCreating(DbModelBuilder modelBuilder) {
         throw new UnintentionalCodeFirstException();
      }

      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
   }
}

การใช้คลาสโดเมน

ชั้นเรียน

namespace DatabaseFirstDemo {

   using System;
   using System.Collections.Generic;
	
   public partial class Course {

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2214:DoNotCallOverridableMethodsInConstructors")]

      public Course() {
         this.Enrollments = new HashSet<Enrollment>();
      }
	
      public int CourseID { get; set; }
      public string Title { get; set; }
      public int Credits { get; set; }
	
      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2227:CollectionPropertiesShouldBeReadOnly")]
			
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }
}

ชั้นนักเรียน

namespace DatabaseFirstDemo {

   using System;
   using System.Collections.Generic; 

   public partial class Student {

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2214:DoNotCallOverridableMethodsInConstructors")]

      public Student() {
         this.Enrollments = new HashSet<Enrollment>();
      }

      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
      public System.DateTime EnrollmentDate { get; set; }

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2227:CollectionPropertiesShouldBeReadOnly")]
			
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }
}

การลงทะเบียนเรียน

namespace DatabaseFirstDemo {

   using System;
   using System.Collections.Generic; 

   public partial class Enrollment {

      public int EnrollmentID { get; set; }
      public int CourseID { get; set; }
      public int StudentID { get; set; }
      public Nullable<int> Grade { get; set; }
		
      public virtual Course Course { get; set; }
      public virtual Student Student { get; set; }
   }
}

สร้างการดำเนินการ

การเพิ่มอ็อบเจ็กต์ใหม่ด้วย Entity Framework ทำได้ง่ายเพียงแค่สร้างอินสแตนซ์ใหม่ของอ็อบเจ็กต์ของคุณและลงทะเบียนโดยใช้เมธอด Add บน DbSet รหัสต่อไปนี้ช่วยให้คุณสามารถเพิ่มนักเรียนใหม่ในฐานข้อมูลได้

class Program {

   static void Main(string[] args) {

      var newStudent = new Student();

      //set student name

      newStudent.FirstMidName = "Bill";
      newStudent.LastName = "Gates";
      newStudent.EnrollmentDate = DateTime.Parse("2015-10-21");
      newStudent.ID = 100;

      //create DBContext object

      using (var dbCtx = new UniContextEntities()) {

         //Add Student object into Students DBset
         dbCtx.Students.Add(newStudent);

         // call SaveChanges method to save student into database
         dbCtx.SaveChanges();
      }
   }
}

อัปเดตการทำงาน

การเปลี่ยนออบเจ็กต์ที่มีอยู่ทำได้ง่ายเพียงแค่อัปเดตค่าที่กำหนดให้กับคุณสมบัติที่คุณต้องการเปลี่ยนแปลงและเรียกใช้ SaveChanges ตัวอย่างเช่นรหัสต่อไปนี้ใช้เพื่อเปลี่ยนนามสกุลของ Ali จาก Khan เป็น Aslam

using (var context = new UniContextEntities()) {

   var student = (from d in context.Students where d.FirstMidName == "Ali" select d).Single();
   student.LastName = "Aslam";
   context.SaveChanges();
}

ลบการทำงาน

ในการลบเอนทิตีโดยใช้ Entity Framework คุณใช้เมธอด Remove บน DbSet ลบงานสำหรับทั้งเอนทิตีที่มีอยู่และเพิ่มใหม่ การเรียกลบในเอนทิตีที่ถูกเพิ่ม แต่ยังไม่ได้บันทึกลงในฐานข้อมูลจะยกเลิกการเพิ่มเอนทิตี เอนทิตีจะถูกลบออกจากตัวติดตามการเปลี่ยนแปลงและไม่ถูกติดตามโดย DbContext อีกต่อไป การเรียกลบในเอนทิตีที่มีอยู่ซึ่งกำลังถูกติดตามการเปลี่ยนแปลงจะลงทะเบียนเอนทิตีสำหรับการลบในครั้งถัดไปที่เรียก SaveChanges ตัวอย่างต่อไปนี้เป็นรหัสที่นักเรียนถูกลบออกจากฐานข้อมูลซึ่งมีชื่อแรกคือ Ali

using (var context = new UniContextEntities()) {
   var bay = (from d in context.Students where d.FirstMidName == "Ali" select d).Single();
   context.Students.Remove(bay);
   context.SaveChanges();
}

อ่านการทำงาน

การอ่านข้อมูลที่มีอยู่จากฐานข้อมูลนั้นง่ายมาก ต่อไปนี้เป็นรหัสที่เรียกข้อมูลทั้งหมดจากตารางนักเรียนจากนั้นโปรแกรมจะแสดงพร้อมชื่อและนามสกุลของนักเรียนตามลำดับตัวอักษร

using (var db = new UniContextEntities()) {

   var query = from b in db.Students orderby b.FirstMidName select b;
   Console.WriteLine("All All student in the database:");

   foreach (var item in query) {
      Console.WriteLine(item.FirstMidName +" "+ item.LastName);
   }

   Console.WriteLine("Press any key to exit...");
   Console.ReadKey();
}

นักพัฒนาด้านการเข้าถึงข้อมูลทุกคนประสบปัญหาในขณะที่ตอบคำถามเกี่ยวกับการทำงานพร้อมกันของข้อมูล "จะเกิดอะไรขึ้นถ้ามีคนมากกว่าหนึ่งคนแก้ไขข้อมูลเดียวกันในเวลาเดียวกัน"

  • ยิ่งโชคดีในหมู่พวกเราที่ต้องรับมือกับกฎทางธุรกิจที่บอกว่า“ ไม่มีปัญหาสุดท้ายก็ชนะ”

  • ในกรณีนี้การเกิดพร้อมกันไม่ใช่ปัญหา เป็นไปได้มากว่ามันไม่ง่ายอย่างนั้นและไม่มีกระสุนเงินที่จะแก้ปัญหาทุกสถานการณ์ในคราวเดียว

  • ตามค่าเริ่มต้น Entity Framework จะใช้เส้นทางของ“ last one in wins” ซึ่งหมายความว่ามีการใช้การอัปเดตล่าสุดแม้ว่าจะมีผู้อื่นอัปเดตข้อมูลระหว่างเวลาที่ดึงข้อมูลและบันทึกข้อมูลเวลา

มาเป็นตัวอย่างให้เข้าใจกันดีกว่า ตัวอย่างต่อไปนี้จะเพิ่มคอลัมน์ใหม่ VersionNo ในตารางหลักสูตร

ไปที่นักออกแบบและคลิกขวาที่หน้าต่างนักออกแบบและเลือกรุ่นอัปเดตจากฐานข้อมูล ...

คุณจะเห็นว่ามีการเพิ่มคอลัมน์อื่นในเอนทิตีหลักสูตร

คลิกขวาที่คอลัมน์ที่สร้างขึ้นใหม่ VersionNo และเลือก Properties และเปลี่ยน ConcurrencyMode เป็น Fixed ดังที่แสดงในภาพต่อไปนี้

ด้วย ConcurrencyMode ของหลักสูตรเวอร์ชันไม่ตั้งค่าเป็นคงที่เมื่อใดก็ตามที่มีการอัปเดตหลักสูตรคำสั่งอัปเดตจะค้นหาหลักสูตรโดยใช้คุณสมบัติของ EntityKey และ VersionNo

ลองมาดูสถานการณ์ง่ายๆ ผู้ใช้สองคนเรียกค้นหลักสูตรเดียวกันในเวลาเดียวกันและผู้ใช้ 1 เปลี่ยนชื่อวิชานั้นเป็นคณิตศาสตร์และบันทึกการเปลี่ยนแปลงก่อนผู้ใช้ 2 ในภายหลังเมื่อผู้ใช้ 2 เปลี่ยนชื่อของหลักสูตรนั้นซึ่งถูกดึงมาก่อนที่ผู้ใช้ 1 จะบันทึกการเปลี่ยนแปลงของเขาในนั้น ผู้ใช้กรณีที่ 2 จะได้รับข้อยกเว้นการเกิดพร้อมกัน"User2: Optimistic Concurrency exception occured".

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;

namespace DatabaseFirstDemo {

   class Program {

      static void Main(string[] args) {

         Course c1 = null;
         Course c2 = null;

         //User 1 gets Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c1 = context.Courses.Where(s ⇒ s.CourseID == 1).Single();
         }

         //User 2 also get the same Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c2 = context.Courses.Where(s ⇒ s.CourseID == 1).Single();
         }

         //User 1 updates Course Title
         c1.Title = "Edited from user1";

         //User 2 updates Course Title
         c2.Title = "Edited from user2";

         //User 1 saves changes first

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c1).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User1: Optimistic Concurrency exception occurred");
            }
         }

         //User 2 saves changes after User 1.
         //User 2 will get concurrency exection
         //because CreateOrModifiedDate is different in the database

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c2).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User2: Optimistic Concurrency exception occurred");
            }
         }
      }
   }
}

ในทุกเวอร์ชันของ Entity Framework เมื่อใดก็ตามที่คุณดำเนินการ SaveChanges()ในการแทรกอัพเดตหรือลบฐานข้อมูลเฟรมเวิร์กจะรวมการดำเนินการนั้นไว้ในธุรกรรม เมื่อคุณเรียกใช้ SaveChanges บริบทจะเริ่มต้นธุรกรรมโดยอัตโนมัติและกระทำหรือย้อนกลับขึ้นอยู่กับว่าการคงอยู่สำเร็จหรือไม่

  • ทั้งหมดนี้เป็นความโปร่งใสสำหรับคุณและคุณไม่จำเป็นต้องจัดการกับมัน

  • ธุรกรรมนี้ใช้เวลานานพอที่จะดำเนินการและเสร็จสิ้น

  • เมื่อคุณดำเนินการดังกล่าวอื่นธุรกรรมใหม่จะเริ่มขึ้น

Entity Framework 6 มีดังต่อไปนี้ -

ฐานข้อมูล BeginTransaction ()

  • เป็นวิธีการที่ง่ายและสะดวกกว่าภายใน DbContext ที่มีอยู่เพื่อเริ่มต้นและทำธุรกรรมให้กับผู้ใช้

  • ช่วยให้สามารถรวมการดำเนินการหลายอย่างภายในธุรกรรมเดียวกันและด้วยเหตุนี้ทั้งหมดจึงมีข้อผูกพันหรือทั้งหมดจะถูกย้อนกลับเป็นรายการเดียว

  • นอกจากนี้ยังช่วยให้ผู้ใช้ระบุระดับการแยกสำหรับธุรกรรมได้ง่ายขึ้น

Database.UseTransaction ()

  • อนุญาตให้ DbContext ใช้ธุรกรรมซึ่งเริ่มต้นนอก Entity Framework

ลองมาดูตัวอย่างต่อไปนี้ซึ่งมีการดำเนินการหลายรายการในธุรกรรมเดียว รหัสเป็น -

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         using (var dbContextTransaction = context.Database.BeginTransaction()) {

            try {

               Student student = new Student() {
                  ID = 200, 
                  FirstMidName = "Ali", 
                  LastName = "Khan", 
                  EnrollmentDate = DateTime.Parse("2015-12-1")
               };

               context.Students.Add(student);

               context.Database.ExecuteSqlCommand(@"UPDATE Course SET Title = 
                  'Calculus'" + "WHERE CourseID = 1045");

               var query = context.Courses.Where(c ⇒ c.CourseID == 1045);

               foreach (var item in query) {
                  Console.WriteLine(item.CourseID.ToString()
                     + " " + item.Title + " " + item.Credits);
               }

               context.SaveChanges();
               var query1 = context.Students.Where(s ⇒ s.ID == 200);

               foreach (var item in query1) {
                  Console.WriteLine(item.ID.ToString() 
                     + " " + item.FirstMidName + " " + item.LastName);
               }

               dbContextTransaction.Commit();
            } catch (Exception) {
               dbContextTransaction.Rollback();
            }

         }
      }
   }
}
  • การเริ่มต้นธุรกรรมจำเป็นต้องเปิดการเชื่อมต่อร้านค้าที่เกี่ยวข้อง

  • ดังนั้นการเรียกใช้ DatabaseBeginTransaction () จะเปิดการเชื่อมต่อหากยังไม่ได้เปิด

  • หาก DbContextTransaction เปิดการเชื่อมต่อการเชื่อมต่อจะปิดเมื่อเรียก Dispose ()

มุมมองคือวัตถุที่มีข้อมูลที่ได้รับจากแบบสอบถามที่กำหนดไว้ล่วงหน้า มุมมองคือวัตถุเสมือนหรือตารางที่ชุดผลลัพธ์ได้มาจากแบบสอบถาม คล้ายกับตารางจริงมากเพราะประกอบด้วยคอลัมน์และแถวของข้อมูล ต่อไปนี้เป็นการใช้มุมมองทั่วไป -

  • กรองข้อมูลของตารางพื้นฐาน
  • กรองข้อมูลเพื่อความปลอดภัย
  • รวมศูนย์ข้อมูลที่กระจายไปทั่วเซิร์ฟเวอร์หลายเครื่อง
  • สร้างชุดข้อมูลที่ใช้ซ้ำได้

มุมมองสามารถใช้ในลักษณะเดียวกันกับที่คุณสามารถใช้ตาราง ในการใช้มุมมองเป็นเอนทิตีก่อนอื่นคุณจะต้องเพิ่มมุมมองฐานข้อมูลไปยัง EDM หลังจากเพิ่มมุมมองให้กับโมเดลของคุณแล้วคุณสามารถทำงานกับมันได้เช่นเดียวกับเอนทิตีปกติยกเว้นการดำเนินการสร้างอัปเดตและลบ

ลองมาดูวิธีเพิ่มมุมมองลงในโมเดลจากฐานข้อมูล

Step 1 - สร้างโครงการแอปพลิเคชันคอนโซลใหม่

Step 2 - คลิกขวาที่โปรเจ็กต์ในตัวสำรวจโซลูชันแล้วเลือกเพิ่ม→รายการใหม่

Step 3 - เลือก ADO.NET Entity Data Model จากบานหน้าต่างตรงกลางและป้อนชื่อ ViewModel ในฟิลด์ Name

Step 4 - คลิกปุ่มเพิ่มซึ่งจะเปิดกล่องโต้ตอบตัวช่วยสร้างโมเดลข้อมูลเอนทิตี

Step 5 - เลือก EF Designer จากฐานข้อมูลและคลิกปุ่มถัดไป

Step 6 - เลือกฐานข้อมูลที่มีอยู่แล้วคลิกถัดไป

Step 7 - เลือก Entity Framework 6.x แล้วคลิกถัดไป

Step 8 - เลือกตารางและมุมมองจากฐานข้อมูลของคุณแล้วคลิกเสร็จสิ้น

คุณสามารถเห็นในหน้าต่างตัวออกแบบว่ามุมมองถูกสร้างขึ้นและคุณสามารถใช้ในโปรแกรมเป็นเอนทิตีได้

ในตัวสำรวจโซลูชันคุณจะเห็นว่าคลาส MyView ถูกสร้างขึ้นจากฐานข้อมูลด้วย

มาดูตัวอย่างที่ดึงข้อมูลทั้งหมดจากมุมมอง ต่อไปนี้เป็นรหัส -

class Program {

   static void Main(string[] args) {

      using (var db = new UniContextEntities()) {

         var query = from b in db.MyViews
            orderby b.FirstMidName select b;

         Console.WriteLine("All student in the database:");

         foreach (var item in query) {
            Console.WriteLine(item.FirstMidName + " " + item.LastName);
         }

         Console.WriteLine("Press any key to exit...");
         Console.ReadKey();
      }
   }
}

เมื่อดำเนินการโค้ดด้านบนคุณจะได้รับผลลัพธ์ต่อไปนี้ -

All student in the database:
Ali Khan
Arturo   finand
Bill Gates
Carson Alexander
Gytis Barzdukas
Laura Norman
Meredith Alonso
Nino Olivetto
Peggy Justice
Yan Li
Press any key to exit...

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ดัชนีคือโครงสร้างข้อมูลบนดิสก์ที่ยึดตามตารางและมุมมอง ดัชนีทำให้การดึงข้อมูลเร็วขึ้นและมีประสิทธิภาพในกรณีส่วนใหญ่ อย่างไรก็ตามการใส่ตารางหรือมุมมองที่มีดัชนีมากเกินไปอาจส่งผลต่อประสิทธิภาพของการดำเนินการอื่น ๆ เช่นการแทรกหรือการอัปเดต

  • การจัดทำดัชนีเป็นคุณลักษณะใหม่ในกรอบงานเอนทิตีที่คุณสามารถปรับปรุงประสิทธิภาพของแอปพลิเคชัน Code First ของคุณได้โดยลดเวลาที่ต้องใช้ในการสืบค้นข้อมูลจากฐานข้อมูล

  • คุณสามารถเพิ่มดัชนีในฐานข้อมูลของคุณโดยใช้ไฟล์ Index แอตทริบิวต์และแทนที่ค่าเริ่มต้น Unique และ Clustered การตั้งค่าเพื่อให้ได้ดัชนีที่เหมาะสมที่สุดกับสถานการณ์ของคุณ

มาดูโค้ดต่อไปนี้ซึ่งมีการเพิ่มแอตทริบิวต์ Index ในคลาส Course สำหรับ CourseID

public partial class Course {

   public Course() {
      this.Enrollments = new HashSet<Enrollment>();
   }

   [Index]
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   public int Credits { get; set; }
   public byte[] VersionNo { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

คีย์ที่สร้างข้างต้นไม่ซ้ำกันไม่ใช่คลัสเตอร์ มีโอเวอร์โหลดที่สามารถลบล้างค่าเริ่มต้นเหล่านี้ได้ -

  • ในการสร้างดัชนีให้เป็นดัชนีแบบคลัสเตอร์คุณต้องระบุ IsClustered = true

  • ในทำนองเดียวกันคุณสามารถสร้างดัชนีให้เป็นดัชนีเฉพาะได้โดยระบุ IsUnique = true

ลองดูรหัส C # ต่อไปนี้ที่ดัชนีเป็นคลัสเตอร์และไม่ซ้ำกัน

public partial class Course {

   public Course() {
      this.Enrollments = new HashSet<Enrollment>();
   }

   [Index(IsClustered = true, IsUnique = true)]
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   public int Credits { get; set; }
   public byte[] VersionNo { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

สามารถใช้แอตทริบิวต์ดัชนีเพื่อสร้างดัชนีเฉพาะในฐานข้อมูล อย่างไรก็ตามนี่ไม่ได้หมายความว่า EF จะสามารถให้เหตุผลเกี่ยวกับความเป็นเอกลักษณ์ของคอลัมน์ได้เมื่อจัดการกับความสัมพันธ์ ฯลฯ โดยทั่วไปแล้วคุณลักษณะนี้จะเรียกว่าการสนับสนุนสำหรับ

Entity Framework อนุญาตให้คุณใช้โพรซีเดอร์ที่เก็บไว้ใน Entity Data Model แทนหรือใช้ร่วมกับการสร้างคำสั่งอัตโนมัติ

  • คุณสามารถใช้กระบวนงานที่จัดเก็บเพื่อดำเนินการตรรกะที่กำหนดไว้ล่วงหน้าบนตารางฐานข้อมูลและหลายองค์กรมีนโยบายที่กำหนดให้ใช้กระบวนงานที่จัดเก็บเหล่านี้

  • นอกจากนี้ยังสามารถระบุว่า EF ควรใช้โพรซีเดอร์ที่จัดเก็บไว้ของคุณสำหรับการแทรกอัปเดตหรือลบเอนทิตี

  • แม้ว่าคำสั่งที่สร้างขึ้นแบบไดนามิกจะปลอดภัยมีประสิทธิภาพและโดยทั่วไปดีเท่ากับหรือดีกว่าคำสั่งที่คุณเขียนเอง แต่ก็มีหลายกรณีที่มีขั้นตอนการจัดเก็บอยู่แล้วและแนวปฏิบัติของ บริษัท ของคุณอาจ จำกัด การใช้ตารางโดยตรง

  • หรือคุณอาจต้องการควบคุมสิ่งที่ดำเนินการในร้านค้าอย่างชัดเจนและต้องการสร้างกระบวนงานที่จัดเก็บไว้

ตัวอย่างต่อไปนี้สร้างโปรเจ็กต์ใหม่จากไฟล์→ใหม่→โปรเจ็กต์

Step 1 - เลือกแอปพลิเคชันคอนโซลจากบานหน้าต่างตรงกลางและป้อน StoredProceduresDemo ในช่องชื่อ

Step 2 - ใน Server explorer คลิกขวาที่ฐานข้อมูลของคุณ

Step 3 - เลือกแบบสอบถามใหม่และป้อนรหัสต่อไปนี้ในตัวแก้ไข T-SQL เพื่อเพิ่มตารางใหม่ในฐานข้อมูลของคุณ

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = 
   OBJECT_ID(N'[dbo].[StudentGrade]') AND type in (N'U'))

BEGIN

   CREATE TABLE [dbo].[StudentGrade](

      [EnrollmentID] [int] IDENTITY(1,1) NOT NULL,
      [CourseID] [int] NOT NULL,
      [StudentID] [int] NOT NULL,
      [Grade] [decimal](3, 2) NULL,

      CONSTRAINT [PK_StudentGrade] PRIMARY KEY CLUSTERED (
         [EnrollmentID] ASC
      )

      WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

   ) ON [PRIMARY]

END
GO

Step 4 - คลิกขวาที่ตัวแก้ไขและเลือกดำเนินการ

Step 5- คลิกขวาที่ฐานข้อมูลของคุณแล้วคลิกรีเฟรช คุณจะเห็นตารางที่เพิ่มใหม่ในฐานข้อมูลของคุณ

Step 6 - ใน Server explorer ให้คลิกขวาที่ฐานข้อมูลของคุณอีกครั้ง

Step 7 - เลือกแบบสอบถามใหม่และป้อนรหัสต่อไปนี้ในตัวแก้ไข T-SQL เพื่อเพิ่มขั้นตอนการจัดเก็บในฐานข้อมูลของคุณซึ่งจะส่งคืนคะแนนของนักเรียน

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = 
   OBJECT_ID(N'[dbo].[GetStudentGrades]') AND type in (N'P', N'PC'))

BEGIN

   EXEC dbo.sp_executesql @statement = N'
   CREATE PROCEDURE [dbo].[GetStudentGrades]
   @StudentID int
   AS
   SELECT EnrollmentID, Grade, CourseID, StudentID FROM dbo.StudentGrade 
   WHERE StudentID = @StudentID
   '
END
GO

Step 8 - คลิกขวาที่ตัวแก้ไขและเลือกดำเนินการ

Step 9- คลิกขวาที่ฐานข้อมูลของคุณแล้วคลิกรีเฟรช คุณจะเห็นว่ามีการสร้างกระบวนงานที่จัดเก็บไว้ในฐานข้อมูลของคุณ

Step 10 - คลิกขวาที่ชื่อโครงการใน Solution Explorer แล้วเลือกเพิ่ม→รายการใหม่

Step 11 - จากนั้นเลือก ADO.NET Entity Data Model ในบานหน้าต่างเทมเพลต

Step 12 - ป้อน SPModel เป็นชื่อจากนั้นคลิกเพิ่ม

Step 13 - ในกล่องโต้ตอบเลือกเนื้อหาแบบจำลองให้เลือกตัวออกแบบ EF จากฐานข้อมูลจากนั้นคลิกถัดไป

Step 14 - เลือกฐานข้อมูลของคุณแล้วคลิกถัดไป

Step 15 - ในกล่องโต้ตอบเลือกวัตถุฐานข้อมูลของคุณให้คลิกที่ตารางมุมมอง

Step 16 - เลือกฟังก์ชัน GetStudentGradesForCourse ที่อยู่ภายใต้โหนด Stored Procedures and Functions แล้วคลิก Finish

Step 17 - เลือก View → Other Windows → Entity Data Model Browser แล้วคลิกขวา GetStudentGrades ภายใต้ Function Imports แล้วเลือก Edit

มันจะสร้างกล่องโต้ตอบต่อไปนี้

Step 18 - คลิกที่ปุ่มตัวเลือกเอนทิตีและเลือก StudentGrade จากคอมโบบ็อกซ์เป็นประเภทการส่งคืนของกระบวนงานที่เก็บไว้นี้แล้วคลิกตกลง

มาดูรหัส C # ต่อไปนี้ซึ่งจะมีการดึงคะแนนทั้งหมดโดยส่งรหัสนักเรียนเป็นพารามิเตอร์ในขั้นตอนการจัดเก็บ GetStudentGrades

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         int studentID = 22;
         var studentGrades = context.GetStudentGrades(studentID);

         foreach (var student in studentGrades) {
            Console.WriteLine("Course ID: {0}, Title: {1}, Grade: {2} ", 
               student.CourseID, student.Course.Title, student.Grade);
         }

         Console.ReadKey();

      }
   }
}

เมื่อโค้ดด้านบนถูกคอมไพล์และดำเนินการคุณจะได้รับผลลัพธ์ต่อไปนี้ -

Course ID: 4022, Title: Microeconomics, Grade: 3.00
Course ID: 4041, Title: Macroeconomics, Grade: 3.50

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ในบทนี้ให้เราดูวิธีการเปลี่ยนแปลงเอนทิตีที่บริบทไม่ถูกติดตาม เอนทิตีที่ไม่ได้ถูกติดตามโดยบริบทเรียกว่าเอนทิตี 'ไม่เชื่อมต่อ'

  • สำหรับแอปพลิเคชันระดับเดียวส่วนใหญ่ที่อินเทอร์เฟซผู้ใช้และเลเยอร์การเข้าถึงฐานข้อมูลทำงานในกระบวนการแอปพลิเคชันเดียวกันคุณอาจจะดำเนินการกับเอนทิตีที่ถูกติดตามโดยบริบท

  • การดำเนินการกับเอนทิตีที่ไม่ได้เชื่อมต่อนั้นพบได้บ่อยในแอปพลิเคชัน N-Tier

  • แอปพลิเคชัน N-Tier เกี่ยวข้องกับการดึงข้อมูลบางอย่างบนเซิร์ฟเวอร์และส่งคืนผ่านเครือข่ายไปยังเครื่องไคลเอนต์

  • จากนั้นไคลเอนต์แอปพลิเคชันจะจัดการข้อมูลนี้ก่อนที่จะส่งคืนไปยังเซิร์ฟเวอร์เพื่อคงอยู่

ต่อไปนี้เป็นสองขั้นตอนที่ต้องดำเนินการกับกราฟเอนทิตีที่ถูกตัดการเชื่อมต่อหรือแม้แต่เอนทิตีที่ถูกตัดการเชื่อมต่อเดียว

  • แนบเอนทิตีด้วยอินสแตนซ์บริบทใหม่และทำให้บริบททราบเกี่ยวกับเอนทิตีเหล่านี้

  • ตั้งค่า EntityStates ที่เหมาะสมให้กับเอนทิตีเหล่านี้ด้วยตนเอง

มาดูโค้ดต่อไปนี้ซึ่งมีการเพิ่มเอนทิตีนักศึกษาด้วยเอนทิตีการลงทะเบียนสองเอนทิตี

class Program {

   static void Main(string[] args) {

      var student = new Student {

         ID = 1001,
         FirstMidName = "Wasim",
         LastName = "Akram", 

         EnrollmentDate = DateTime.Parse("2015-10-10"), 
            Enrollments = new List<Enrollment> {

               new Enrollment{EnrollmentID = 2001,CourseID = 4022, StudentID = 1001 },
               new Enrollment{EnrollmentID = 2002,CourseID = 4025, StudentID = 1001 },
         }
      };

      using (var context = new UniContextEntities()) {

         context.Students.Add(student);
         Console.WriteLine("New Student ({0} {1}): {2}", 
            student.FirstMidName, student.LastName, context.Entry(student).State);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0} State: {1}", 
               enrollment.EnrollmentID, context.Entry(enrollment).State);
         }

         Console.WriteLine("Press any key to exit...");
         Console.ReadKey();
      }
   } 
}
  • โค้ดนี้สร้างอินสแตนซ์ Student ใหม่ซึ่งอ้างอิงอินสแตนซ์การลงทะเบียนใหม่สองอินสแตนซ์ในคุณสมบัติการลงทะเบียน

  • จากนั้นนักเรียนใหม่จะถูกเพิ่มลงในบริบทโดยใช้วิธีการเพิ่ม

  • เมื่อเพิ่ม Student แล้วโค้ดจะใช้เมธอด DbContext.Entry เพื่อเข้าถึงข้อมูลการติดตามการเปลี่ยนแปลงที่ Entity Framework มีเกี่ยวกับ Student ใหม่

  • จากข้อมูลการติดตามการเปลี่ยนแปลงนี้คุณสมบัติของรัฐจะใช้เพื่อเขียนสถานะปัจจุบันของเอนทิตี

  • จากนั้นกระบวนการนี้จะทำซ้ำสำหรับการลงทะเบียนที่สร้างขึ้นใหม่แต่ละรายการที่อ้างอิงจากนักเรียนใหม่ หากคุณเรียกใช้แอปพลิเคชันคุณจะได้รับผลลัพธ์ต่อไปนี้ -

New Student   (Wasim  Akram): Added
Enrollment ID: 2001 State: Added
Enrollment ID: 2002 State: Added
Press any key to exit...

ในขณะที่ DbSet.Add ใช้เพื่อบอก Entity Framework เกี่ยวกับเอนทิตีใหม่ DbSet.Attach ใช้เพื่อบอก Entity Framework เกี่ยวกับเอนทิตีที่มีอยู่ วิธีการแนบจะทำเครื่องหมายเอนทิตีในสถานะไม่เปลี่ยนแปลง

ลองดูรหัส C # ต่อไปนี้ซึ่งแนบเอนทิตีที่ไม่ได้เชื่อมต่อกับ DbContext

class Program {

   static void Main(string[] args) {

      var student = new Student {

         ID = 1001,
         FirstMidName = "Wasim",
         LastName = "Akram",
         EnrollmentDate = DateTime.Parse("2015-10-10"), 

         Enrollments = new List<Enrollment> {
            new Enrollment { EnrollmentID = 2001, CourseID = 4022, StudentID = 1001 },
            new Enrollment { EnrollmentID = 2002, CourseID = 4025, StudentID = 1001 },
         }
			
      };

      using (var context = new UniContextEntities()) {

         context.Students.Attach(student);
         Console.WriteLine("New Student ({0} {1}): {2}", 
            student.FirstMidName, student.LastName, context.Entry(student).State);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0} State: {1}", enrollment.EnrollmentID, 
               context.Entry(enrollment).State);
         }

         Console.WriteLine("Press any key to exit...");
         Console.ReadKey();
      }
   }
}

เมื่อโค้ดด้านบนถูกเรียกใช้ด้วยเมธอด Attach () คุณจะได้รับผลลัพธ์ต่อไปนี้

New Student   (Wasim  Akram): Unchanged
Enrollment ID: 2001 State: Unchanged
Enrollment ID: 2002 State: Unchanged
Press any key to exit...

ในบทนี้ให้เราเรียนรู้วิธีการแมป Table-valueed Functions (TVF) โดยใช้ Entity Framework Designer และวิธีเรียก TVF จากแบบสอบถาม LINQ

  • ปัจจุบันรองรับ TVF ในเวิร์กโฟลว์ Database First เท่านั้น

  • เปิดตัวครั้งแรกใน Entity Framework เวอร์ชัน 5

  • ในการใช้ TVF คุณต้องกำหนดเป้าหมาย. NET Framework 4.5 ขึ้นไป

  • คล้ายกับขั้นตอนการจัดเก็บ แต่มีข้อแตกต่างที่สำคัญอย่างหนึ่งคือผลลัพธ์ของ TVF สามารถประกอบได้ ซึ่งหมายความว่าผลลัพธ์จาก TVF สามารถใช้ในแบบสอบถาม LINQ ได้ในขณะที่ไม่สามารถใช้ผลลัพธ์ของกระบวนงานที่เก็บไว้ได้

มาดูตัวอย่างการสร้างโปรเจ็กต์ใหม่จาก File → New → Project ต่อไปนี้

Step 1 - เลือกแอปพลิเคชันคอนโซลจากบานหน้าต่างตรงกลางและป้อน TableValuedFunctionDemo ในช่องชื่อ

Step 2 - ใน Server explorer คลิกขวาที่ฐานข้อมูลของคุณ

Step 3 - เลือกแบบสอบถามใหม่และป้อนรหัสต่อไปนี้ในตัวแก้ไข T-SQL เพื่อเพิ่มตารางใหม่ในฐานข้อมูลของคุณ

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id =
   OBJECT_ID(N'[dbo].[StudentGrade]') AND type in (N'U'))

BEGIN

   CREATE TABLE [dbo].[StudentGrade](

      [EnrollmentID] [int] IDENTITY(1,1) NOT NULL,
      [CourseID] [int] NOT NULL,
      [StudentID] [int] NOT NULL,
      [Grade] [decimal](3, 2) NULL,

      CONSTRAINT [PK_StudentGrade] PRIMARY KEY CLUSTERED ([EnrollmentID] ASC)

      WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

   ) ON [PRIMARY]

END
GO

Step 4 - คลิกขวาที่ตัวแก้ไขและเลือกดำเนินการ

Step 5- คลิกขวาที่ฐานข้อมูลของคุณแล้วคลิกรีเฟรช คุณจะเห็นตารางที่เพิ่มใหม่ในฐานข้อมูลของคุณ

Step 6- ตอนนี้สร้างฟังก์ชันที่จะคืนเกรดของนักเรียนสำหรับหลักสูตร ป้อนรหัสต่อไปนี้ในตัวแก้ไข T-SQL

CREATE FUNCTION [dbo].[GetStudentGradesForCourse]

(@CourseID INT)

RETURNS TABLE

RETURN
   SELECT [EnrollmentID],
      [CourseID],
      [StudentID],
      [Grade]
   FROM   [dbo].[StudentGrade]
   WHERE  CourseID = @CourseID

Step 7 - คลิกขวาที่ตัวแก้ไขและเลือกดำเนินการ

ตอนนี้คุณจะเห็นว่าฟังก์ชันถูกสร้างขึ้น

Step 8 - คลิกขวาที่ชื่อโครงการใน Solution Explorer แล้วเลือกเพิ่ม→รายการใหม่

Step 9 - จากนั้นเลือก ADO.NET Entity Data Model ในบานหน้าต่างเทมเพลต

Step 10 - ป้อน TVFModel เป็นชื่อจากนั้นคลิกเพิ่ม

Step 11 - ในกล่องโต้ตอบเลือกเนื้อหาแบบจำลองให้เลือกตัวออกแบบ EF จากฐานข้อมูลจากนั้นคลิกถัดไป

Step 12 - เลือกฐานข้อมูลของคุณแล้วคลิกถัดไป

Step 13 - ในกล่องโต้ตอบเลือกวัตถุฐานข้อมูลของคุณให้เลือกตารางมุมมอง

Step 14 - เลือกฟังก์ชัน GetStudentGradesForCourse ที่อยู่ภายใต้โหนด Stored Procedures and Functions แล้วคลิก Finish

Step 15 - เลือก View → Other Windows → Entity Data Model Browser แล้วคลิกขวา GetStudentGradesForCourse ภายใต้ Function Imports แล้วเลือก Edit

คุณจะเห็นกล่องโต้ตอบต่อไปนี้

Step 16 - คลิกที่ปุ่มตัวเลือกเอนทิตีและเลือกการลงทะเบียนจากคอมโบบ็อกซ์เป็นประเภทการส่งคืนของฟังก์ชันนี้และคลิกตกลง

มาดูรหัส C # ต่อไปนี้ซึ่งจะมีการดึงคะแนนของนักเรียนทั้งหมดที่ลงทะเบียนเรียนใน Course ID = 4022 ในฐานข้อมูล

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         var CourseID = 4022;

         // Return all the best students in the Microeconomics class.
         var students = context.GetStudentGradesForCourse(CourseID);

         foreach (var result in students) {
            Console.WriteLine("Student ID:  {0}, Grade: {1}",
               result.StudentID, result.Grade);
         }

         Console.ReadKey();
      }
   }
}

เมื่อโค้ดด้านบนถูกคอมไพล์และดำเนินการคุณจะได้รับผลลัพธ์ต่อไปนี้ -

Student ID: 1, Grade: 2
Student ID: 4, Grade: 4
Student ID: 9, Grade: 3.5

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ใน Entity Framework คุณสามารถสอบถามกับคลาสเอนทิตีของคุณโดยใช้ LINQ คุณยังสามารถเรียกใช้แบบสอบถามโดยใช้ SQL ดิบโดยตรงกับฐานข้อมูลโดยใช้ DbCOntext เทคนิคนี้สามารถนำไปใช้กับโมเดลที่สร้างด้วย Code First และ EF Designer ได้อย่างเท่าเทียมกัน

แบบสอบถาม SQL ในเอนทิตีที่มีอยู่

วิธี SqlQuery บน DbSet อนุญาตให้เขียนแบบสอบถาม SQL ดิบที่จะส่งคืนอินสแตนซ์ของเอนทิตี อ็อบเจ็กต์ที่ส่งคืนจะถูกติดตามโดยบริบทเช่นเดียวกับที่พวกมันถูกส่งคืนโดยคิวรี LINQ ตัวอย่างเช่น -

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         var students = context.Students.SqlQuery("SELECT * FROM dbo.Student").ToList();

         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}, \tEnrollment Date {2} ",
               student.ID, name, student.EnrollmentDate.ToString());
         }

         Console.ReadKey();
      }
   }
}

รหัสด้านบนจะดึงข้อมูลนักเรียนทั้งหมดจากฐานข้อมูล

แบบสอบถาม SQL สำหรับประเภทที่ไม่ใช่เอนทิตี

แบบสอบถาม SQL ที่ส่งคืนอินสแตนซ์ทุกประเภทรวมถึงชนิดดั้งเดิมสามารถสร้างได้โดยใช้เมธอด SqlQuery บนคลาสฐานข้อมูล ตัวอย่างเช่น -

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         var studentNames = context.Database.SqlQuery
            <string>("SELECT FirstMidName FROM dbo.Student").ToList();

         foreach (var student in studentNames) {
            Console.WriteLine("Name: {0}", student);
         }

         Console.ReadKey();
      }
   }
}

คำสั่ง SQL ไปยังฐานข้อมูล

เมธอด ExecuteSqlCommnad ใช้ในการส่งคำสั่งที่ไม่ใช่คิวรีไปยังฐานข้อมูลเช่นคำสั่ง Insert, Update หรือ Delete มาดูรหัสต่อไปนี้ซึ่งมีการอัปเดตชื่อของนักเรียนเป็น ID = 1

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         //Update command

         int noOfRowUpdated = context.Database.ExecuteSqlCommand("Update 
            student set FirstMidName = 'Ali' where ID = 1");

         context.SaveChanges();

         var student = context.Students.SqlQuery("SELECT * FROM
            dbo.Student where ID = 1").Single();

         string name = student.FirstMidName + " " + student.LastName;

         Console.WriteLine("ID: {0}, Name: {1}, \tEnrollment Date {2} ", 
            student.ID, name, student.EnrollmentDate.ToString());

         Console.ReadKey();
      }
   }
}

รหัสด้านบนจะดึงชื่อของนักเรียนทั้งหมดจากฐานข้อมูล

ใน Entity Framework คุณลักษณะนี้จะช่วยให้คุณกำหนดคุณสมบัติบนคลาสโดเมนที่เป็นประเภท enum และแม็พกับคอลัมน์ฐานข้อมูลประเภทจำนวนเต็ม จากนั้น Entity Framework จะแปลงค่าฐานข้อมูลเป็นและจาก enum ที่เกี่ยวข้องในขณะที่ทำการค้นหาและบันทึกข้อมูล

  • ประเภทที่แจกแจงมีประโยชน์ทุกประเภทเมื่อทำงานกับคุณสมบัติที่มีจำนวนการตอบสนองคงที่

  • ทั้งความปลอดภัยและความน่าเชื่อถือของแอปพลิเคชันจะเพิ่มขึ้นเมื่อคุณใช้การแจงนับ

  • การแจงนับทำให้ผู้ใช้ทำผิดได้ยากขึ้นมากและปัญหาต่างๆเช่นการโจมตีด้วยการฉีดก็ไม่มีอยู่

  • ใน Entity Framework การแจงนับสามารถมีประเภทพื้นฐานดังต่อไปนี้ -

    • Byte
    • Int16
    • Int32
    • Int64
    • SByte
  • ชนิดพื้นฐานเริ่มต้นขององค์ประกอบการแจงนับคือ int

  • โดยค่าเริ่มต้นตัวแจงนับตัวแรกจะมีค่า 0 และค่าของแต่ละตัวแจงนับต่อเนื่องจะเพิ่มขึ้น 1

ลองดูตัวอย่างต่อไปนี้ซึ่งเราจะสร้างเอนทิตีในตัวออกแบบจากนั้นจะเพิ่มคุณสมบัติบางอย่าง

Step 1 - สร้างโครงการใหม่จากไฟล์→ใหม่→ตัวเลือกเมนูโครงการ

Step 2 - ในบานหน้าต่างด้านซ้ายเลือกแอปพลิเคชันคอนโซล

Step 3 - ป้อน EFEnumDemo เป็นชื่อโครงการแล้วคลิกตกลง

Step 4 - คลิกขวาที่ชื่อโครงการใน Solution Explorer และเลือกเพิ่ม→ตัวเลือกเมนูรายการใหม่

Step 5 - เลือก ADO.NET Entity Data Model ในบานหน้าต่างเทมเพลต

Step 6 - ป้อน EFEnumModel.edmx สำหรับชื่อไฟล์จากนั้นคลิกเพิ่ม

Step 7 - ในหน้าตัวช่วยสร้างโมเดลข้อมูลเอนทิตีเลือก Empty EF designer Model

Step 8 - คลิกเสร็จสิ้น

Step 9 - จากนั้นคลิกขวาที่หน้าต่างนักออกแบบและเลือกเพิ่ม→เอนทิตี

กล่องโต้ตอบ New Entity จะปรากฏดังที่แสดงในภาพต่อไปนี้

Step 10 - ป้อน Department เป็นชื่อเอนทิตีและ DeptID เป็นชื่อคุณสมบัติปล่อยให้ประเภทคุณสมบัติเป็น Int32 แล้วคลิกตกลง

Step 11 - คลิกขวาที่เอนทิตีแล้วเลือกเพิ่มใหม่→คุณสมบัติสเกลาร์

Step 12 - เปลี่ยนชื่อคุณสมบัติใหม่เป็น DeptName

Step 13 - เปลี่ยนประเภทของคุณสมบัติใหม่เป็น Int32 (โดยค่าเริ่มต้นคุณสมบัติใหม่เป็นประเภท String)

Step 14 - หากต้องการเปลี่ยนประเภทให้เปิดหน้าต่าง Properties และเปลี่ยนคุณสมบัติ Type เป็น Int32

Step 15 - ใน Entity Framework Designer คลิกขวาที่คุณสมบัติ Name เลือก Convert to enum

Step 16 - ในกล่องโต้ตอบ Add Enum Type ให้ป้อน DepartmentNames สำหรับ Enum Type Name เปลี่ยน Underlying Type เป็น Int32 จากนั้นเพิ่มสมาชิกต่อไปนี้ให้กับประเภท: Physics, Chemistry, Computer และ Economics

Step 17 - คลิกตกลง

หากคุณเปลี่ยนไปใช้หน้าต่าง Model Browser คุณจะเห็นว่ามีการเพิ่มประเภทลงในโหนด Enum types ด้วย

มาสร้างฐานข้อมูลจากโมเดลโดยทำตามขั้นตอนทั้งหมดที่กล่าวถึงในบทแนวทางแรกของโมเดล

Step 1 - คลิกขวาที่พื้นผิว Entity Designer แล้วเลือกสร้างฐานข้อมูลจาก Model

กล่องโต้ตอบเลือกการเชื่อมต่อข้อมูลของตัวช่วยสร้างฐานข้อมูลจะปรากฏขึ้น

Step 2 - คลิกปุ่มการเชื่อมต่อใหม่

Step 3 - ป้อนชื่อเซิร์ฟเวอร์และ EnumDemo สำหรับฐานข้อมูลแล้วคลิกตกลง

Step 4 - กล่องโต้ตอบถามว่าคุณต้องการสร้างฐานข้อมูลใหม่หรือไม่จะปรากฏขึ้นให้คลิกใช่

Step 5- คลิกถัดไปและสร้างตัวช่วยสร้างฐานข้อมูลจะสร้างภาษานิยามข้อมูล (DDL) สำหรับสร้างฐานข้อมูล ตอนนี้คลิกเสร็จสิ้น

Step 6 - คลิกขวาที่ T-SQL Editor แล้วเลือก Execute

Step 7 - หากต้องการดูสคีมาที่สร้างขึ้นให้คลิกขวาที่ชื่อฐานข้อมูลใน SQL Server Object Explorer และเลือกรีเฟรช

คุณจะเห็นตารางแผนกในฐานข้อมูล

ลองมาดูตัวอย่างต่อไปนี้ซึ่งมีการเพิ่มและบันทึกวัตถุแผนกใหม่ในบริบท จากนั้นเรียกข้อมูลแผนกคอมพิวเตอร์

class Program {

   static void Main(string[] args) {

      using (var context = new EFEnumModelContainer()) {

         context.Departments.Add(new Department { DeptName = DepartmentNames.Physics});
         context.Departments.Add(new Department { DeptName = DepartmentNames.Computer});
         context.Departments.Add(new Department { DeptName = DepartmentNames.Chemistry});
         context.Departments.Add(new Department { DeptName = DepartmentNames.Economics});

         context.SaveChanges();

         var department = (
            from d in context.Departments
            where d.DeptName == DepartmentNames.Computer
            select d
         ).FirstOrDefault();

         Console.WriteLine(
            "Department ID: {0}, Department Name: {1}", 
               department.DeptID, department.DeptName
         );

         Console.ReadKey();
      }
   }
}

เมื่อดำเนินการโค้ดด้านบนคุณจะได้รับผลลัพธ์ต่อไปนี้ -

Department ID: 2, Department Name: Computer

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

Asynchronous programmingเกี่ยวข้องกับการดำเนินการในพื้นหลังเพื่อให้เธรดหลักสามารถดำเนินการต่อไปได้ วิธีนี้เธรดหลักสามารถรักษาการตอบสนองของอินเทอร์เฟซผู้ใช้ในขณะที่เธรดพื้นหลังกำลังประมวลผลงานในมือ

  • Entity Framework 6.0 สนับสนุนการดำเนินการแบบอะซิงโครนัสสำหรับการสืบค้นและการบันทึกข้อมูล

  • การดำเนินการแบบอะซิงโครนัสสามารถช่วยแอปพลิเคชันของคุณได้ดังต่อไปนี้ -

    • ทำให้แอปพลิเคชันของคุณตอบสนองต่อการโต้ตอบของผู้ใช้มากขึ้น
    • ปรับปรุงประสิทธิภาพโดยรวมของแอปพลิเคชันของคุณ
  • คุณสามารถดำเนินการแบบอะซิงโครนัสได้หลายวิธี แต่คำหลัก async / await ถูกนำมาใช้ใน. NET Framework 4.5 ซึ่งทำให้งานของคุณง่ายขึ้น

  • สิ่งเดียวที่คุณต้องปฏิบัติตามคือรูปแบบ async / await ตามที่แสดงในส่วนของรหัสต่อไปนี้

ลองดูตัวอย่างต่อไปนี้ (โดยไม่ใช้ async / await) ซึ่งเมธอด DatabaseOperations จะบันทึกนักเรียนใหม่ลงในฐานข้อมูลจากนั้นดึงข้อมูลนักเรียนทั้งหมดจากฐานข้อมูลและในตอนท้ายจะมีการพิมพ์ข้อความเพิ่มเติมบนคอนโซล

class Program {

   static void Main(string[] args) {
      Console.WriteLine("Database Operations Started");
      DatabaseOperations();
		
      Console.WriteLine();
      Console.WriteLine("Database Operations Completed");
      Console.WriteLine();
      Console.WriteLine("Entity Framework Tutorials");
      Console.ReadKey();
   }

   public static void DatabaseOperations() {

      using (var context = new UniContextEntities()) {

         // Create a new student and save it

         context.Students.Add(new Student {
            FirstMidName = "Akram", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())});

         Console.WriteLine("Calling SaveChanges.");
         context.SaveChanges();
         Console.WriteLine("SaveChanges completed.");

         // Query for all Students ordered by first name

         var students = (from s in context.Students
            orderby s.FirstMidName select s).ToList();

         // Write all students out to Console

         Console.WriteLine();
         Console.WriteLine("All Student:");

         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine(" " + name);
         }
      }
   }
}

เมื่อดำเนินการโค้ดด้านบนคุณจะได้รับผลลัพธ์ต่อไปนี้ -

Calling SaveChanges.
SaveChanges completed.
All Student:
Akram Khan
Ali Khan
Ali Alexander
Arturo Anand
Bill Gates
Gytis Barzdukas
Laura  Nornan
Meredith fllonso
Nino Olioetto
Peggy Justice
Yan Li

Entity Framework Tutorials

มาใช้ async ใหม่และรอคำสำคัญและทำการเปลี่ยนแปลงต่อไปนี้กับ Program.cs

  • เพิ่ม System.Data.Entity namespace ซึ่งจะให้วิธีการขยาย EF async

  • เพิ่ม System.Threading.Tasks namespace ซึ่งจะช่วยให้เราใช้งานประเภท Task

  • อัปเดต DatabaseOperations ที่จะทำเครื่องหมายเป็น async และส่งคืนไฟล์ Task.

  • เรียกใช้ SaveChanges เวอร์ชัน Async และรอให้เสร็จสิ้น

  • เรียกใช้ ToList เวอร์ชัน Async และรอผล

class Program {

   static void Main(string[] args) {
      var task = DatabaseOperations();
      Console.WriteLine();
      Console.WriteLine("Entity Framework Tutorials");
      task.Wait();
      Console.ReadKey();
   }

   public static async Task DatabaseOperations() {

      using (var context = new UniContextEntities()) {

         // Create a new blog and save it

         context.Students.Add(new Student {
            FirstMidName = "Salman", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())});

         Console.WriteLine("Calling SaveChanges.");
         await context.SaveChangesAsync();
         Console.WriteLine("SaveChanges completed.");

         // Query for all Students ordered by first name

         var students = await (from s in context.Students 
            orderby s.FirstMidName select s).ToListAsync();

         // Write all students out to Console

         Console.WriteLine();
         Console.WriteLine("All Student:");

         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName; 
            Console.WriteLine(" " + name);
         }
      }
   }
}

ในการดำเนินการจะให้ผลลัพธ์ดังต่อไปนี้

Calling SaveChanges.
Entity Framework Tutorials
SaveChanges completed.
All Student:
Akram Khan
Ali Khan
Ali Alexander
Arturo Anand
Bill Gates
Gytis Barzdukas
Laura  Nornan
Meredith fllonso
Nino Olioetto
Peggy Justice
Salman Khan
Yan Li

เมื่อโค้ดเป็นแบบอะซิงโครนัสแล้วคุณสามารถสังเกตขั้นตอนการดำเนินการที่แตกต่างกันของโปรแกรมของคุณได้

  • SaveChanges เริ่มส่ง Student ใหม่ไปยังฐานข้อมูลจากนั้นเมธอด DatabaseOperations จะส่งกลับ (แม้ว่าจะยังไม่เสร็จสิ้นการดำเนินการ) และขั้นตอนของโปรแกรมในเมธอดหลักยังคง

  • จากนั้นข้อความจะถูกเขียนลงในคอนโซล

  • เธรดที่มีการจัดการจะถูกบล็อกในการรอสายจนกว่าการดำเนินการฐานข้อมูลจะเสร็จสิ้น เมื่อดำเนินการเสร็จสิ้นส่วนที่เหลือของ DatabaseOperations ของเราจะถูกดำเนินการ

  • SaveChanges เสร็จสมบูรณ์

  • ดึงข้อมูลนักเรียนทั้งหมดจากฐานข้อมูลและเขียนลงในคอนโซล

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ตอนนี้ Entity Framework ช่วยให้คุณได้รับประโยชน์จาก Entity Framework โดยไม่ต้องบังคับให้ทุกส่วนของแอปพลิเคชันของคุณต้องตระหนักถึง Entity Framework แยกเอนทิตีออกจากโครงสร้างพื้นฐาน คุณสามารถสร้างชั้นเรียนที่สามารถมุ่งเน้นไปที่กฎทางธุรกิจของพวกเขาได้โดยไม่ต้องคำนึงถึงวิธีการคงอยู่ (ที่จัดเก็บข้อมูลและวิธีที่ข้อมูลกลับไปกลับมาระหว่างออบเจ็กต์ของคุณ)

การสร้างเอนทิตีที่เพิกเฉยต่อเนื่อง

ย่อหน้าก่อนหน้านี้อธิบายถึงวิธีการที่ไม่มีความรู้อย่างใกล้ชิดเกี่ยวกับแหล่งที่มาของข้อมูลที่ใช้ สิ่งนี้เน้นถึงสาระสำคัญของความไม่รู้ที่คงอยู่ซึ่งก็คือเมื่อชั้นเรียนของคุณและเลเยอร์แอปพลิเคชันจำนวนมากของเราอยู่รอบ ๆ พวกเขาไม่สนใจว่าข้อมูลจะถูกจัดเก็บอย่างไร

  • ใน Entity Framework เวอร์ชัน. NET 3.5 หากคุณต้องการใช้คลาสที่มีอยู่ก่อนคุณจะต้องแก้ไขโดยบังคับให้ได้มาจาก EntityObject

  • ใน. NET 4 สิ่งนี้ไม่จำเป็นอีกต่อไป คุณไม่จำเป็นต้องแก้ไขเอนทิตีของคุณเพื่อให้พวกเขามีส่วนร่วมในการดำเนินการของ Entity Framework

  • สิ่งนี้ช่วยให้เราสร้างแอปพลิเคชันที่รองรับการเชื่อมต่อแบบหลวม ๆ และการแยกข้อกังวล

  • ด้วยรูปแบบการเข้ารหัสเหล่านี้ชั้นเรียนของคุณจะเกี่ยวข้องกับงานของตนเองเท่านั้นและหลาย ๆ ชั้นของแอปพลิเคชันของคุณรวมถึง UI จะไม่มีการพึ่งพาตรรกะภายนอกเช่น Entity Framework APIs แต่ API ภายนอกเหล่านั้นสามารถโต้ตอบกับเราได้ เอนทิตี

มี 2 ​​วิธี (เชื่อมต่อและตัดการเชื่อมต่อ) เมื่อยังคงมีเอนทิตีด้วย Entity Framework ทั้งสองทางมีความสำคัญในตัวเอง ในกรณีของสถานการณ์จำลองที่เชื่อมต่อการเปลี่ยนแปลงจะถูกติดตามโดยบริบท แต่ในกรณีของสถานการณ์ที่ขาดการเชื่อมต่อเราจำเป็นต้องแจ้งบริบทเกี่ยวกับสถานะของเอนทิตี

สถานการณ์ที่เชื่อมต่อ

สถานการณ์ที่เชื่อมต่อคือเมื่อมีการดึงข้อมูลเอนทิตีจากฐานข้อมูลและแก้ไขในบริบทเดียวกัน สำหรับสถานการณ์ที่เชื่อมต่อกันให้เราสมมติว่าเรามีบริการ Windows และเรากำลังดำเนินการทางธุรกิจกับเอนทิตีนั้นดังนั้นเราจะเปิดบริบทวนรอบเอนทิตีทั้งหมดดำเนินการทางธุรกิจของเราแล้วบันทึกการเปลี่ยนแปลงด้วยบริบทเดียวกันกับที่เรา เปิดตั้งแต่ต้น

มาดูตัวอย่างต่อไปนี้ที่นักเรียนดึงข้อมูลจากฐานข้อมูลและอัปเดตชื่อของนักเรียนจากนั้นบันทึกการเปลี่ยนแปลงลงในฐานข้อมูล

class Program {

   static void Main(string[] args) {

      using (var context = new MyContext()) {

         var studentList = context.Students.ToList();

         foreach (var stdnt in studentList) {
            stdnt.FirstMidName = "Edited " + stdnt.FirstMidName;
         }

         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.ReadKey();
      }
   }
}

เมื่อโค้ดด้านบนถูกคอมไพล์และดำเนินการคุณจะได้รับผลลัพธ์ต่อไปนี้และคุณจะเห็นว่า Edited word ถูกแนบมาก่อนชื่อดังที่แสดงในผลลัพธ์ต่อไปนี้

Retrieve all Students from the database: 
ID: 1, Name: Edited Edited Alain Bomer 
ID: 2, Name: Edited Edited Mark Upston

สถานการณ์ที่ไม่เชื่อมต่อ

สถานการณ์ที่ไม่เชื่อมต่อคือเมื่อมีการดึงข้อมูลเอนทิตีจากฐานข้อมูลและแก้ไขในบริบทที่แตกต่างกัน สมมติว่าเราต้องการแสดงข้อมูลบางส่วนใน Presentation Layer และเรากำลังใช้แอปพลิเคชัน n-tier ดังนั้นจึงเป็นการดีกว่าที่จะเปิดบริบทดึงข้อมูลและปิดบริบทในที่สุด เนื่องจากที่นี่เราได้ดึงข้อมูลและปิดบริบทเอนทิตีที่เราดึงข้อมูลจึงไม่ถูกติดตามอีกต่อไปและนี่คือสถานการณ์ที่ขาดการเชื่อมต่อ

มาดูโค้ดต่อไปนี้ซึ่งมีการเพิ่มเอนทิตี Student ที่ไม่ได้เชื่อมต่อใหม่ลงในบริบทโดยใช้วิธีการเพิ่ม

class Program {

   static void Main(string[] args) {

      var student = new Student {
         ID = 1001, 
         FirstMidName = "Wasim", 
         LastName = "Akram", 
         EnrollmentDate = DateTime.Parse( DateTime.Today.ToString())
      };

      using (var context = new MyContext()) {

         context.Students.Add(student);
         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.ReadKey();
      }
   }
}

เมื่อโค้ดด้านบนถูกคอมไพล์และดำเนินการคุณจะได้รับผลลัพธ์ต่อไปนี้

Retrieve all Students from the database:
ID: 1, Name: Edited Edited Edited Alain Bomer
ID: 2, Name: Edited Edited Edited Mark Upston
ID: 3, Name: Wasim Akram

LINQ ถึงเอนทิตี

แนวคิดที่สำคัญที่สุดอย่างหนึ่งในการทำความเข้าใจ LINQ to Entities คือภาษาที่ใช้ในการประกาศ โฟกัสอยู่ที่การกำหนดว่าคุณต้องการข้อมูลอะไรมากกว่าที่จะได้รับข้อมูล

  • หมายความว่าคุณสามารถใช้เวลาในการทำงานกับข้อมูลได้มากขึ้นและใช้เวลาน้อยลงในการพยายามหารหัสพื้นฐานที่จำเป็นในการทำงานต่างๆเช่นการเข้าถึงฐานข้อมูล

  • สิ่งสำคัญคือต้องเข้าใจว่าภาษาที่ใช้ในการประกาศไม่ได้ลบการควบคุมใด ๆ จากนักพัฒนา แต่จะช่วยให้นักพัฒนามุ่งความสนใจไปที่สิ่งที่สำคัญ

LINQ to Entities คีย์เวิร์ดสำคัญ

สิ่งสำคัญคือต้องทราบคำหลักพื้นฐานที่ใช้ในการสร้างแบบสอบถาม LINQ มีคำหลักเพียงไม่กี่คำที่ต้องจำ แต่คุณสามารถรวมเข้าด้วยกันได้หลายวิธีเพื่อให้ได้ผลลัพธ์ที่เฉพาะเจาะจง รายการต่อไปนี้ประกอบด้วยคำหลักพื้นฐานเหล่านี้และให้คำอธิบายง่ายๆของแต่ละคำ

เลขที่ คำหลักและคำอธิบาย
1

Ascending

ระบุว่าการดำเนินการเรียงลำดับเกิดขึ้นจากองค์ประกอบน้อยที่สุด (หรือต่ำสุด) ของช่วงถึงองค์ประกอบสูงสุดของช่วง โดยปกติเป็นการตั้งค่าเริ่มต้น ตัวอย่างเช่นเมื่อทำการเรียงลำดับตามตัวอักษรการเรียงลำดับจะอยู่ในช่วงตั้งแต่ A ถึง Z

2

By

ระบุฟิลด์หรือนิพจน์ที่ใช้ในการจัดกลุ่ม ฟิลด์หรือนิพจน์กำหนดคีย์ที่ใช้เพื่อดำเนินการจัดกลุ่ม

3

Descending

ระบุว่าการดำเนินการเรียงลำดับเกิดขึ้นจากองค์ประกอบที่ยิ่งใหญ่ที่สุด (หรือสูงสุด) ของช่วงไปยังองค์ประกอบที่ต่ำที่สุดของช่วง ตัวอย่างเช่นเมื่อทำการเรียงลำดับตามตัวอักษรการเรียงลำดับจะอยู่ในช่วงตั้งแต่ Z ถึง A

4

Equals

ใช้ระหว่างส่วนคำสั่งด้านซ้ายและด้านขวาของคำสั่ง join เพื่อรวมแหล่งข้อมูลตามบริบทหลักกับแหล่งข้อมูลบริบทรอง ฟิลด์หรือนิพจน์ทางด้านซ้ายของคีย์เวิร์ดเท่ากับระบุแหล่งข้อมูลหลักในขณะที่ฟิลด์หรือนิพจน์ทางด้านขวาของคีย์เวิร์ดเท่ากับระบุแหล่งข้อมูลรอง

5

From

ระบุแหล่งข้อมูลที่ใช้เพื่อรับข้อมูลที่ต้องการและกำหนดตัวแปรช่วง ตัวแปรนี้มีจุดประสงค์เดียวกับตัวแปรที่ใช้สำหรับการวนซ้ำ

6

Group

จัดระเบียบเอาต์พุตเป็นกลุ่มโดยใช้ค่าคีย์ที่คุณระบุ ใช้กลุ่มคำสั่งหลายกลุ่มเพื่อสร้างองค์กรเอาต์พุตหลายระดับ ลำดับของประโยคกลุ่มจะกำหนดความลึกที่ค่าคีย์หนึ่ง ๆ ปรากฏในลำดับการจัดกลุ่ม คุณรวมคำหลักนี้เข้ากับ by เพื่อสร้างบริบทเฉพาะ

7

In

ใช้ในหลายวิธี ในกรณีนี้คีย์เวิร์ดจะกำหนดแหล่งฐานข้อมูลบริบทที่ใช้สำหรับคิวรี เมื่อทำงานกับการเข้าร่วมคีย์เวิร์ด in จะใช้สำหรับแหล่งฐานข้อมูลบริบทแต่ละแหล่งที่ใช้สำหรับการเข้าร่วม

8

Into

ระบุตัวระบุที่คุณสามารถใช้เป็นข้อมูลอ้างอิงสำหรับส่วนคำสั่งการสืบค้น LINQ เช่นเข้าร่วมกลุ่มและเลือก

9

Join

สร้างแหล่งข้อมูลเดียวจากแหล่งข้อมูลที่เกี่ยวข้องสองแหล่งเช่นในการตั้งค่าหลัก / รายละเอียด การรวมสามารถระบุการรวมภายในกลุ่มหรือการรวมด้านซ้ายโดยให้การรวมภายในเป็นค่าเริ่มต้น คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการรวมได้ที่msdn.microsoft.com

10

Let

กำหนดตัวแปรช่วงที่คุณสามารถใช้เพื่อเก็บผลลัพธ์นิพจน์ย่อยในนิพจน์แบบสอบถาม โดยทั่วไปตัวแปร range จะใช้เพื่อจัดเตรียมเอาต์พุตที่แจกแจงเพิ่มเติมหรือเพื่อเพิ่มประสิทธิภาพของแบบสอบถาม (เพื่อให้งานเฉพาะเช่นการค้นหาค่าตัวพิมพ์เล็กของสตริงไม่จำเป็นต้องทำมากกว่าหนึ่งครั้ง)

11

On

ระบุฟิลด์หรือนิพจน์ที่ใช้เพื่อใช้การรวม ฟิลด์หรือนิพจน์กำหนดองค์ประกอบที่ใช้ร่วมกันกับแหล่งข้อมูลตามบริบททั้งสอง

12

Orderby

สร้างลำดับการจัดเรียงสำหรับแบบสอบถาม คุณสามารถเพิ่มคีย์เวิร์ดจากน้อยไปมากหรือมากไปหาน้อยเพื่อควบคุมลำดับของการจัดเรียง ใช้คำสั่ง orderby หลายคำเพื่อสร้างการเรียงลำดับหลายระดับ ลำดับของคำสั่ง orderby จะกำหนดลำดับการจัดการนิพจน์การเรียงลำดับดังนั้นการใช้ลำดับที่แตกต่างกันจะทำให้ได้ผลลัพธ์ที่แตกต่างกัน

13

Where

กำหนดสิ่งที่ LINQ ควรดึงจากแหล่งข้อมูล คุณใช้นิพจน์บูลีนอย่างน้อยหนึ่งรายการเพื่อกำหนดลักษณะเฉพาะของสิ่งที่จะดึงข้อมูล นิพจน์บูลีนถูกแยกออกจากกันโดยใช้เครื่องหมาย && (AND) และ || (หรือ) ตัวดำเนินการ

14

Select

กำหนดผลลัพธ์จากแบบสอบถาม LINQ โดยระบุข้อมูลที่จะส่งคืน คำสั่งนี้กำหนดชนิดข้อมูลขององค์ประกอบที่ LINQ ส่งคืนในระหว่างกระบวนการวนซ้ำ

การฉายภาพ

แบบสอบถามการฉายภาพช่วยเพิ่มประสิทธิภาพของแอปพลิเคชันของคุณโดยการดึงเฉพาะฟิลด์ที่ระบุจากฐานข้อมูลของคุณ

  • เมื่อคุณมีข้อมูลแล้วคุณอาจต้องการฉายหรือกรองตามความจำเป็นเพื่อกำหนดรูปร่างข้อมูลก่อนที่จะส่งออก

  • งานหลักของนิพจน์ LINQ to Entities คือการรับข้อมูลและจัดเตรียมเป็นเอาต์พุต

ส่วน“ การพัฒนา LINQ to Entities queries” ของบทนี้แสดงให้เห็นถึงเทคนิคในการดำเนินงานพื้นฐานนี้

มาดูโค้ดต่อไปนี้ว่าจะเรียกข้อมูลรายชื่อนักเรียนใดบ้าง

using (var context = new UniContextEntities()) {

   var studentList = from s in context.Students select s;

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }
}

วัตถุเดี่ยว

ในการดึงอ็อบเจ็กต์นักเรียนเดี่ยวคุณสามารถใช้วิธีการนับ First () หรือ FirstOrDefault ซึ่งส่งคืนองค์ประกอบแรกของลำดับ ความแตกต่างระหว่าง First และ FirstOrDefault คือ First () จะทำให้เกิดข้อยกเว้นหากไม่มีข้อมูลผลลัพธ์สำหรับเกณฑ์ที่ให้มาในขณะที่ FirstOrDefault () จะส่งคืนค่าเริ่มต้นเป็น null หากไม่มีข้อมูลผลลัพธ์ ในข้อมูลโค้ดด้านล่างนี้นักเรียนคนแรกจากรายชื่อจะถูกดึงข้อมูลซึ่งมีชื่อแรกคือ Ali

using (var context = new UniContextEntities()) {

   var student = (from s in context.Students where s.FirstMidName 
      == "Ali" select s).FirstOrDefault<Student>();

   string name = student.FirstMidName + " " + student.LastName;
   Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
}

คุณยังสามารถใช้ Single () หรือ SingleOrDefault เพื่อรับอ็อบเจ็กต์นักเรียนเดี่ยวซึ่งส่งคืนองค์ประกอบเดียวที่เฉพาะเจาะจงของลำดับ ในตัวอย่างต่อไปนี้นักเรียนคนเดียวจะถูกดึงข้อมูลซึ่งมี ID คือ 2

using (var context = new UniContextEntities()) {

   var student = (from s in context.Students where s.ID 
      == 2 select s).SingleOrDefault<Student>();
   string name = student.FirstMidName + " " + student.LastName;
	
   Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   Console.ReadKey();
}

รายชื่อวัตถุ

หากคุณต้องการดึงข้อมูลรายชื่อนักเรียนที่มีนามสกุลของ Ali คุณสามารถใช้ ToList () วิธีการแจงนับ

using (var context = new UniContextEntities()) {

   var studentList = (from s in context.Students where s.FirstMidName 
      == "Ali" select s).ToList();

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }

   Console.ReadKey();
}

ใบสั่ง

ในการดึงข้อมูล / รายการตามลำดับใด ๆ คุณสามารถใช้คำหลัก orderby ในรหัสต่อไปนี้รายชื่อตัวอย่างของนักเรียนจะถูกเรียกดูตามลำดับจากน้อยไปมาก

using (var context = new UniContextEntities()) {

   var studentList = (from s in context.Students orderby
      s.FirstMidName ascending select s).ToList();

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }

   Console.ReadKey();
}

แบบสอบถามกรอบเอนทิตีมาตรฐาน Vs

สมมติว่าคุณมีโมเดล Student ที่มี ID, FirstMidName, LastName และ EnrollmentDate หากคุณต้องการส่งคืนรายชื่อนักเรียนแบบสอบถามมาตรฐานจะส่งคืนฟิลด์ทั้งหมด แต่ถ้าคุณต้องการรับเฉพาะรายชื่อนักเรียนที่มีฟิลด์ ID, FirstMidName และ LastName นี่คือที่ที่คุณควรใช้แบบสอบถามการฉายภาพ ต่อไปนี้เป็นตัวอย่างง่ายๆของแบบสอบถามการฉายภาพ

using (var context = new UniContextEntities()) {

   var studentList = from s in context.Students
      orderby s.FirstMidName ascending
      where s.FirstMidName == "Ali"

   select new {s.ID, s.FirstMidName, s.LastName};

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }

   Console.ReadKey();
}

แบบสอบถามการฉายภาพด้านบนไม่รวมฟิลด์ EnrollmentDate สิ่งนี้จะทำให้แอปพลิเคชันของคุณเร็วขึ้นมาก

ใน Entity Framework 6.0 มีการแนะนำคุณลักษณะใหม่ซึ่งเรียกว่า Logging SQL. ในขณะที่ทำงานกับ Entity Framework จะส่งคำสั่งหรือแบบสอบถาม SQL ที่เทียบเท่าไปยังฐานข้อมูลเพื่อดำเนินการ CRUD (สร้างอ่านอัปเดตและลบ)

  • คุณลักษณะนี้ของ Entity Framework คือการรวบรวมแบบสอบถาม SQL ที่เทียบเท่าซึ่งสร้างโดย Entity Framework ภายในและจัดให้เป็นผลลัพธ์

  • ก่อน Entity Framework 6 เมื่อใดก็ตามที่จำเป็นต้องติดตามคิวรีและคำสั่งฐานข้อมูลนักพัฒนาไม่มีทางเลือกนอกจากใช้ยูทิลิตี้การติดตามของบุคคลที่สามหรือเครื่องมือติดตามฐานข้อมูล

  • ใน Entity Framework 6 คุณลักษณะใหม่นี้มีวิธีง่ายๆโดยการบันทึกการดำเนินการทั้งหมดที่ดำเนินการโดย Entity Framework

  • กิจกรรมทั้งหมดที่ดำเนินการโดย Entity Framework จะถูกบันทึกโดยใช้ DbContext.Database.Log

มาดูรหัสต่อไปนี้ที่มีการเพิ่มนักเรียนใหม่ลงในฐานข้อมูล

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Database.Log = Console.Write;

         // Create a new student and save it

         context.Students.Add(new Student {
            FirstMidName = "Salman", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         context.SaveChanges();
         Console.ReadKey();
      }
   }
}

เมื่อดำเนินการโค้ดด้านบนคุณจะได้รับผลลัพธ์ต่อไปนี้ซึ่งจริงๆแล้วคือบันทึกของกิจกรรมทั้งหมดที่ดำเนินการโดย EF ในโค้ดด้านบน

Opened connection at 10/28/2015 6:27:35 PM +05:00
Started transaction at 10/28/2015 6:27:35 PM +05:00
INSERT [dbo].[Student]([LastName], [FirstMidName], [EnrollmentDate])
VALUES (@0, @1, @2)
SELECT [ID]
FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [ID] = scope_identity()
-- @0: 'Khan' (Type = String, Size = -1)
-- @1: 'Salman' (Type = String, Size = -1)
-- @2: '10/28/2015 12:00:00 AM' (Type = DateTime)
-- Executing at 10/28/2015 6:27:35 PM +05:00
-- Completed in 5 ms with result: SqlDataReader
Committed transaction at 10/28/2015 6:27:35 PM +05:00
Closed connection at 10/28/2015 6:27:35 PM +05:00

เมื่อคุณสมบัติ Log ถูกตั้งค่ากิจกรรมต่อไปนี้จะถูกบันทึก -

  • SQL สำหรับคำสั่งประเภทต่างๆเช่นแบบสอบถามรวมถึงการแทรกการอัปเดตและการลบที่สร้างขึ้นโดยเป็นส่วนหนึ่งของ SaveChanges

  • Parameters

  • ไม่ว่าจะมีการเรียกใช้คำสั่งแบบอะซิงโครนัสหรือไม่

  • การประทับเวลาที่ระบุเมื่อคำสั่งเริ่มดำเนินการ

  • คำสั่งเสร็จสมบูรณ์หรือล้มเหลว

  • การบ่งชี้บางอย่างของค่าผลลัพธ์

  • ระยะเวลาโดยประมาณที่ใช้ในการดำเนินการคำสั่ง

การเข้าสู่สถานที่อื่น

หากคุณมีเฟรมเวิร์กการบันทึกอยู่แล้วและกำหนดวิธีการบันทึกคุณสามารถบันทึกไปยังที่อื่นได้

ลองดูตัวอย่างต่อไปนี้ซึ่งเรามี MyLogger คลาสอื่น

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Database.Log = s ⇒ MyLogger.Log("EFLoggingDemo", s);

         // Create a new student and save it

         context.Students.Add(new Student {
            FirstMidName = "Salman", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         context.SaveChanges();
         Console.ReadKey();
      }
   }
}

public class MyLogger {

   public static void Log(string application, string message) {
      Console.WriteLine("Application: {0}, EF Message: {1} ",application, message);
   }
}

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ใน Entity Framework 6.0 มีคุณลักษณะใหม่อื่นที่เรียกว่า Interceptorหรือการสกัดกั้น รหัสการสกัดกั้นถูกสร้างขึ้นตามแนวคิดของinterception interfaces. ตัวอย่างเช่นอินเทอร์เฟซ IDbCommandInterceptor กำหนดเมธอดที่ถูกเรียกก่อนที่ EF จะเรียกใช้ ExecuteNonQuery, ExecuteScalar, ExecuteReader และวิธีการที่เกี่ยวข้อง

  • Entity Framework สามารถเปล่งประกายได้อย่างแท้จริงโดยใช้การสกัดกั้น การใช้วิธีนี้ช่วยให้คุณสามารถเก็บข้อมูลได้มากขึ้นชั่วคราวโดยไม่ต้องแก้รหัสของคุณ

  • ในการดำเนินการนี้คุณต้องสร้างตัวสกัดกั้นที่กำหนดเองและลงทะเบียนตามนั้น

  • เมื่อสร้างคลาสที่ใช้อินเทอร์เฟซ IDbCommandInterceptor แล้วจะสามารถลงทะเบียนกับ Entity Framework โดยใช้คลาส DbInterception

  • อินเทอร์เฟซ IDbCommandInterceptor มีหกวิธีและคุณต้องใช้วิธีการเหล่านี้ทั้งหมด ต่อไปนี้เป็นการใช้งานขั้นพื้นฐานของวิธีการเหล่านี้

มาดูโค้ดต่อไปนี้ที่ใช้อินเทอร์เฟซ IDbCommandInterceptor

public class MyCommandInterceptor : IDbCommandInterceptor {

   public static void Log(string comm, string message) {
      Console.WriteLine("Intercepted: {0}, Command Text: {1} ", comm, message);
   }

   public void NonQueryExecuted(DbCommand command, 
      DbCommandInterceptionContext<int> interceptionContext) {
         Log("NonQueryExecuted: ", command.CommandText);
   }

   public void NonQueryExecuting(DbCommand command, 
      DbCommandInterceptionContext<int> interceptionContext) {
         Log("NonQueryExecuting: ", command.CommandText);
   }

   public void ReaderExecuted(DbCommand command, 
      DbCommandInterceptionContext<DbDataReader> interceptionContext) {
         Log("ReaderExecuted: ", command.CommandText);
   }

   public void ReaderExecuting(DbCommand command, 
      DbCommandInterceptionContext<DbDataReader> interceptionContext) {
         Log("ReaderExecuting: ", command.CommandText);
   }

   public void ScalarExecuted(DbCommand command, 
      DbCommandInterceptionContext<object> interceptionContext) {
         Log("ScalarExecuted: ", command.CommandText);
   }

   public void ScalarExecuting(DbCommand command, 
      DbCommandInterceptionContext<object> interceptionContext) {
         Log("ScalarExecuting: ", command.CommandText);
   }

}

การลงทะเบียน Interceptors

เมื่อสร้างคลาสที่ใช้อินเทอร์เฟซการสกัดกั้นอย่างน้อยหนึ่งคลาสแล้วจะสามารถลงทะเบียนกับ EF โดยใช้คลาส DbInterception ดังที่แสดงในโค้ดต่อไปนี้

DbInterception.Add(new MyCommandInterceptor());

นอกจากนี้ยังสามารถลงทะเบียนตัวสกัดกั้นที่ระดับโดเมนแอปโดยใช้การกำหนดค่าตามรหัส DbConfiguration ดังที่แสดงในรหัสต่อไปนี้

public class MyDBConfiguration : DbConfiguration {

   public MyDBConfiguration() {
      DbInterception.Add(new MyCommandInterceptor());
   }
}

คุณยังสามารถกำหนดค่าไฟล์กำหนดค่า interceptor โดยใช้รหัส -

<entityFramework>
   <interceptors>
      <interceptor type = "EFInterceptDemo.MyCommandInterceptor, EFInterceptDemo"/>
   </interceptors>
</entityFramework>

การสนับสนุนประเภทเชิงพื้นที่ถูกนำมาใช้ใน Entity Framework 5 ชุดของตัวดำเนินการรวมอยู่ด้วยเพื่อให้แบบสอบถามวิเคราะห์ข้อมูลเชิงพื้นที่ ตัวอย่างเช่นข้อความค้นหาสามารถกรองตามระยะทางระหว่างสถานที่ตั้งทางภูมิศาสตร์สองแห่ง

  • Entity Framework จะอนุญาตให้ประเภทข้อมูลเชิงพื้นที่ใหม่เปิดเผยเป็นคุณสมบัติบนคลาสของคุณและแมปกับคอลัมน์เชิงพื้นที่ในฐานข้อมูลของคุณ

  • นอกจากนี้คุณยังสามารถเขียนข้อความค้นหา LINQ ที่ใช้ตัวดำเนินการเชิงพื้นที่เพื่อกรองเรียงลำดับและจัดกลุ่มตามการคำนวณเชิงพื้นที่ที่ดำเนินการในฐานข้อมูล

มีข้อมูลเชิงพื้นที่สองประเภทหลัก -

  • ประเภทข้อมูลทางภูมิศาสตร์จะจัดเก็บข้อมูลรูปไข่ตัวอย่างเช่นพิกัดละติจูด GPS และลองจิจูด

  • ชนิดข้อมูลเรขาคณิตแสดงถึงระบบพิกัดแบบยุคลิด (แบน)

ลองมาดูตัวอย่างของสนามคริกเก็ตต่อไปนี้

Step 1 - สร้างโครงการใหม่จากไฟล์→ใหม่→ตัวเลือกเมนูโครงการ

Step 2 - ในบานหน้าต่างด้านซ้ายเลือกแอปพลิเคชันคอนโซล

Step 3 - คลิกขวาที่ชื่อโครงการและเลือกจัดการ NuGet Packages ...

Step 4 - ติดตั้ง Entity Framework

Step 5 - เพิ่มการอ้างอิงไปยังแอสเซมบลี System.Data.Entity และเพิ่ม System.Data.Spatial โดยใช้คำสั่งสำหรับชนิดข้อมูลเชิงพื้นที่

Step 6 - เพิ่มคลาสต่อไปนี้ในไฟล์ Program.cs

public class CricketGround {
   public int ID { get; set; }
   public string Name { get; set; }
   public DbGeography Location { get; set; }
}

Step 7 - นอกเหนือจากการกำหนดเอนทิตีคุณต้องกำหนดคลาสที่มาจาก DbContext และแสดงคุณสมบัติ DbSet <TEntity>

ใน Program.cs เพิ่มนิยามบริบท

public partial class CricketGroundContext : DbContext {
   public DbSet<CricketGround> CricketGrounds { get; set; }
}

Step 8 - เพิ่มรหัสต่อไปนี้ลงในฟังก์ชันหลักซึ่งจะเพิ่มวัตถุ CricketGround ใหม่สองรายการในบริบท

class Program {

   static void Main(string[] args) {

      using (var context = new CricketGroundContext()) {

         context.CricketGrounds.Add(new CricketGround() {
            Name = "Shalimar Cricket Ground", 
            Location = DbGeography.FromText("POINT(-122.336106 47.605049)"), 
         });

         context.CricketGrounds.Add(new CricketGround() {
            Name = "Marghazar Stadium", Location = DbGeography
               .FromText("POINT(-122.335197 47.646711)"), 
         });

         context.SaveChanges();

         var myLocation = DbGeography.FromText("POINT(-122.296623 47.640405)");

         var cricketGround = (from cg in context.CricketGrounds
            orderby cg.Location.Distance(myLocation) select cg).FirstOrDefault();

         Console.WriteLine("The closest Cricket Ground to you is: {0}.", cricketGround.Name);
      }
   }
}

คุณสมบัติเชิงพื้นที่เริ่มต้นโดยใช้วิธี DbGeography.FromText จุดภูมิศาสตร์ที่แสดงเป็น WellKnownText จะถูกส่งผ่านไปยังเมธอดจากนั้นจึงบันทึกข้อมูล หลังจากนั้นวัตถุ CricketGround จะถูกเรียกคืนโดยที่ตำแหน่งของมันอยู่ใกล้กับตำแหน่งที่ระบุมากที่สุด

เมื่อดำเนินการโค้ดด้านบนคุณจะได้รับผลลัพธ์ต่อไปนี้ -

The closest Cricket Ground to you is: Marghazar Stadium

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

การสืบทอดทำให้สามารถสร้างแบบจำลองที่ซับซ้อนซึ่งสะท้อนวิธีคิดของนักพัฒนาได้ดีขึ้นและยังลดงานที่ต้องใช้ในการโต้ตอบกับโมเดลเหล่านั้น การสืบทอดที่ใช้กับเอนทิตีมีจุดประสงค์เดียวกับการสืบทอดที่ใช้กับคลาสดังนั้นนักพัฒนาจึงทราบพื้นฐานของการทำงานของคุณลักษณะนี้อยู่แล้ว

ลองดูตัวอย่างต่อไปนี้และโดยการสร้างโครงการแอปพลิเคชันคอนโซลใหม่

Step 1 - เพิ่ม ADO.NET Entity Data Model โดยคลิกขวาที่ชื่อโปรเจ็กต์แล้วเลือกเพิ่ม→รายการใหม่ ...

Step 2 - เพิ่มเอนทิตีหนึ่งรายการและตั้งชื่อเป็นบุคคลโดยทำตามขั้นตอนทั้งหมดที่กล่าวถึงในบทแนวทางแรกของโมเดล

Step 3 - เพิ่มคุณสมบัติสเกลาร์ตามที่แสดงในภาพต่อไปนี้

Step 4 - เราจะเพิ่มอีกสองเอนทิตี Student และ Teacherซึ่งจะสืบทอดคุณสมบัติจาก Person Table

Step 5 - ตอนนี้เพิ่มเอนทิตีนักเรียนและเลือกบุคคลจากคอมโบบ็อกซ์ประเภทพื้นฐานดังที่แสดงในภาพต่อไปนี้

Step 6 - เพิ่มเอนทิตีครูในทำนองเดียวกัน

Step 7 - ตอนนี้เพิ่มคุณสมบัติสเกลาร์ EnrollmentDate ให้กับเอนทิตีนักเรียนและคุณสมบัติ HireDate ไปยังเอนทิตีครู

Step 8 - มาสร้างฐานข้อมูลกันเลย

Step 9 - คลิกขวาที่พื้นผิวการออกแบบและเลือกสร้างฐานข้อมูลจากแบบจำลอง ...

Step 10- ในการสร้างฐานข้อมูลใหม่ให้คลิกที่การเชื่อมต่อใหม่ ... กล่องโต้ตอบต่อไปนี้จะเปิดขึ้น คลิกตกลง

Step 11- คลิกเสร็จสิ้น สิ่งนี้จะเพิ่มไฟล์ * .edmx.sql ในโปรเจ็กต์ คุณสามารถรันสคริปต์ DDL ใน Visual Studio ได้โดยเปิดไฟล์. sql ตอนนี้คลิกขวาและเลือกดำเนินการ

Step 12 - ไปที่ server explorer คุณจะเห็นว่าฐานข้อมูลถูกสร้างขึ้นด้วยตารางสามตารางที่ระบุไว้

Step 13 - คุณยังสามารถดูได้ว่าคลาสโดเมนต่อไปนี้จะถูกสร้างขึ้นโดยอัตโนมัติ

public partial class Person {
   public int ID { get; set; }
   public string FirstMidName { get; set; }
   public string LastName { get; set; }
}

public partial class Student : Person {
   public System.DateTime EnrollmentDate { get; set; }
}

public partial class Teacher : Person {
   public System.DateTime HireDate { get; set; }
}

ต่อไปนี้เป็นคลาสบริบท

public partial class InheritanceModelContainer : DbContext {

   public InheritanceModelContainer() : 
      base("name = InheritanceModelContainer") {}

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      throw new UnintentionalCodeFirstException();
   }

   public virtual DbSet<Person> People { get; set; }
}

มาเพิ่มนักเรียนและครูบางส่วนในฐานข้อมูลแล้วดึงข้อมูลจากฐานข้อมูล

class Program {

   static void Main(string[] args) {

      using (var context = new InheritanceModelContainer()) {

         var student = new Student {
            FirstMidName = "Meredith", 
            LastName = "Alonso", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(student);

         var student1 = new Student {
            FirstMidName = "Arturo", 
            LastName = "Anand", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(student1);

         var techaer = new Teacher {
            FirstMidName = "Peggy", 
            LastName = "Justice", 
            HireDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(techaer);

         var techaer1 = new Teacher {
            FirstMidName = "Yan", 
            LastName = "Li", 
            HireDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(techaer1);
         context.SaveChanges();
      }
   }
}

มีการเพิ่มนักเรียนและครูในฐานข้อมูล NT เพื่อดึงข้อมูลนักเรียนและครูไฟล์OfType จำเป็นต้องใช้วิธีการซึ่งจะส่งคืนนักเรียนและครูที่เกี่ยวข้องกับแผนกที่ระบุ

Console.WriteLine("All students in database"); 
Console.WriteLine("");

foreach (var student in context.People.OfType<Student>()) {
   string name = student.FirstMidName + " " + student.LastName;
   Console.WriteLine("ID: {0}, Name: {1}, \tEnrollment Date {2} ", 
      student.ID, name, student.EnrollmentDate.ToString());
}

Console.WriteLine("");
Console.WriteLine("************************************************************ *****");
Console.WriteLine("");
Console.WriteLine("All teachers in database");
Console.WriteLine("");

foreach (var teacher in context.People.OfType<Teacher>()) {
   string name = teacher.FirstMidName + " " + teacher.LastName;
   Console.WriteLine("ID: {0}, Name: {1}, \tHireDate {2} ", 
      teacher.ID, name, teacher.HireDate.ToString()); 
}

Console.WriteLine("");
Console.WriteLine("************************************************************ *****");
Console.ReadKey();

ในแบบสอบถามแรกเมื่อคุณใช้ OfType <Student> () คุณจะไม่สามารถเข้าถึง HireDate ได้เนื่องจากคุณสมบัติ HireDate เป็นส่วนหนึ่งของ Teacher Entity และคุณสมบัติ EnrollmentDate ในทำนองเดียวกันจะไม่สามารถเข้าถึงได้เมื่อคุณใช้ OfType <Teacher> ()

เมื่อดำเนินการโค้ดด้านบนคุณจะได้รับผลลัพธ์ต่อไปนี้ -

All students in database
ID: 1, Name: Meredith Alonso,   Enrollment Date 10/30/2015 12:00:00 AM
ID: 2, Name: Arturo Anand,      Enrollment Date 10/30/2015 12:00:00 AM
*****************************************************************  
All teachers in database
ID: 3, Name: Peggy Justice,     HireDate 10/30/2015 12:00:00 AM
ID: 4, Name: Yan Li,    HireDate 10/30/2015 12:00:00 AM
*****************************************************************

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ใน Entity Framework 5 และ Entity Framework เวอร์ชันก่อนหน้ารหัสจะถูกแบ่งระหว่างไลบรารีหลัก (โดยหลักคือ System.Data.Entity.dll) ที่จัดส่งเป็นส่วนหนึ่งของ. NET Framework และไลบรารีเพิ่มเติม (โดยหลักคือ EntityFramework.dll) ถูกแจกจ่ายและ จัดส่งโดยใช้ NuGet ดังแสดงในแผนภาพต่อไปนี้

ใน Entity Framework 6 นั้น API หลักซึ่งก่อนหน้านี้เคยเป็นส่วนหนึ่งของเฟรมเวิร์ก. NET จะถูกจัดส่งและแจกจ่ายเป็นส่วนหนึ่งของแพ็คเกจ NuGet

สิ่งนี้จำเป็นเพื่อให้ Entity Framework เป็นโอเพ่นซอร์ส อย่างไรก็ตามจะต้องสร้างแอปพลิเคชันใหม่เมื่อใดก็ตามที่จำเป็นต้องโยกย้ายหรืออัปเกรดแอปพลิเคชันของคุณจาก Entity Framework เวอร์ชันเก่าไปเป็น EF 6

ขั้นตอนการย้ายข้อมูลนั้นตรงไปตรงมาหากแอปพลิเคชันของคุณใช้ DbContext ซึ่งจัดส่งใน EF 4.1 และใหม่กว่า แต่ถ้าแอปพลิเคชันของคุณเป็น ObjectContext ก็ต้องทำงานเพิ่มขึ้นเล็กน้อย

มาดูขั้นตอนต่อไปนี้ที่คุณต้องทำเพื่ออัปเกรดแอปพลิเคชันที่มีอยู่เป็น EF6

Step 1 - ขั้นตอนแรกคือกำหนดเป้าหมาย. NET Framework 4.5.2 และคลิกขวาที่โปรเจ็กต์ของคุณในภายหลังและเลือกคุณสมบัติ

Step 2 - คลิกขวาที่โครงการของคุณอีกครั้งและเลือกจัดการ NuGet Packages ...

Step 3- ใต้แท็บออนไลน์เลือก EntityFramework แล้วคลิกติดตั้ง ตรวจสอบให้แน่ใจว่าการอ้างอิงแอสเซมบลีไปยัง System.Data.Entity.dll ถูกลบออก

เมื่อคุณติดตั้งแพ็คเกจ EF6 NuGet ควรลบการอ้างอิงถึง System.Data.Entity ออกจากโปรเจ็กต์ของคุณโดยอัตโนมัติ

Step 4 - หากคุณมีโมเดลใด ๆ ที่สร้างด้วย EF Designer คุณจะต้องอัปเดตเทมเพลตการสร้างโค้ดเพื่อสร้างโค้ดที่เข้ากันได้กับ EF6

Step 5 - ใน Solution Explorer ของคุณภายใต้ไฟล์ edmx ของคุณให้ลบเทมเพลตการสร้างโค้ดที่มีอยู่ซึ่งโดยทั่วไปจะมีชื่อว่า <edmx_file_name> .tt และ <edmx_file_name> .Context.tt

Step 6 - เปิดแบบจำลองของคุณใน EF Designer คลิกขวาที่พื้นผิวการออกแบบแล้วเลือกเพิ่มรหัสสร้างรายการ ...

Step 7 - เพิ่มเทมเพลตการสร้างโค้ด EF 6.x ที่เหมาะสม

นอกจากนี้ยังสร้างรหัสที่เข้ากันได้กับ EF6 โดยอัตโนมัติ

หากแอปพลิเคชันของคุณใช้ EF 4.1 หรือใหม่กว่าคุณไม่จำเป็นต้องเปลี่ยนแปลงอะไรในโค้ดเนื่องจากเนมสเปซสำหรับประเภท DbContext และ Code First ไม่ได้เปลี่ยนแปลง

แต่ถ้าแอปพลิเคชันของคุณใช้ Entity Framework เวอร์ชันเก่าให้พิมพ์ ObjectContext ที่เคยอยู่ใน System.Data.Entity.dll ไปยังเนมสเปซใหม่

Step 8 - คุณจะต้องอัปเดตคำสั่งการใช้หรือนำเข้าเพื่อสร้างเทียบกับ EF6

กฎทั่วไปสำหรับการเปลี่ยนแปลงเนมสเปซคือประเภทใด ๆ ใน System.Data. * จะถูกย้ายไปที่ System.Data.Entity.Core. * ต่อไปนี้คือบางส่วนของพวกเขา -

  • System.Data.EntityException ⇒ System.Data.Entity.Core.EntityException
  • System.Data.Objects.ObjectContext ⇒ System.Data.Entity.Core.Objects.ObjectContext;
  • System.Data.Objects.DataClasses.RelationshipManager ⇒ System.Data.Entity.Core.Objects.DataClasses.RelationshipManager;

บางชนิดอยู่ในเนมสเปซหลักเนื่องจากไม่ได้ใช้โดยตรงสำหรับแอปพลิเคชันที่ใช้ DbContext ส่วนใหญ่

  • System.Data.EntityState ⇒ System.Data.Entity.EntityState
  • System.Data.Objects.DataClasses.EdmFunctionAttribute ⇒ System.Data.Entity.DbFunctionAttribute

โครงการ Entity Framework ที่คุณมีอยู่จะทำงานใน Entity Framework 6.0 โดยไม่มีการเปลี่ยนแปลงที่สำคัญใด ๆ

การโหลดอย่างกระตือรือร้นเป็นกระบวนการที่เคียวรีสำหรับเอนทิตีประเภทหนึ่งจะโหลดเอนทิตีที่เกี่ยวข้องเป็นส่วนหนึ่งของคิวรีด้วย การโหลดที่กระตือรือร้นทำได้โดยการใช้ไฟล์Include method.

หมายความว่าการร้องขอข้อมูลที่เกี่ยวข้องจะถูกส่งคืนพร้อมกับผลลัพธ์การสืบค้นจากฐานข้อมูล มีการเชื่อมต่อเพียงครั้งเดียวกับแหล่งข้อมูลข้อมูลจำนวนมากจะถูกส่งกลับในแบบสอบถามเริ่มต้น

ตัวอย่างเช่นเมื่อสอบถามนักเรียนให้โหลดการลงทะเบียนของตนอย่างกระตือรือร้น นักเรียนและการลงทะเบียนของพวกเขาจะถูกเรียกค้นในแบบสอบถามเดียว

มาดูตัวอย่างต่อไปนี้ซึ่งนักเรียนทุกคนที่มีการลงทะเบียนตามลำดับจะถูกดึงข้อมูลจากฐานข้อมูลโดยใช้การโหลดอย่างกระตือรือร้น

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {
         // Load all students and related enrollments
         var students = context.Students
            .Include(s ⇒ s.Enrollments).ToList();
			
         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
				
            foreach (var enrollment in student.Enrollments) {
               Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
                  enrollment.EnrollmentID, enrollment.CourseID);
            }
         }

         Console.ReadKey();
      }
   }
}

เมื่อโค้ดด้านบนถูกคอมไพล์และดำเนินการคุณจะได้รับผลลัพธ์ต่อไปนี้

ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
ID: 2, Name: Meredith Alonso
       Enrollment ID: 4, Course ID: 1045
       Enrollment ID: 5, Course ID: 3141
       Enrollment ID: 6, Course ID: 2021
ID: 3, Name: Arturo Anand
       Enrollment ID: 7, Course ID: 1050
ID: 4, Name: Gytis Barzdukas
       Enrollment ID: 8, Course ID: 1050
       Enrollment ID: 9, Course ID: 4022

ด้านล่างนี้คือรูปแบบอื่น ๆ ของการค้นหาที่ต้องการโหลดซึ่งสามารถใช้ได้

// Load one Student and its related enrollments

var student1 = context.Students
   .Where(s ⇒ s.FirstMidName == "Ali")
   .Include(s ⇒ s.Enrollments).FirstOrDefault();

// Load all Students and related enrollments
// using a string to specify the relationship

var studentList = context.Students
   .Include("Enrollments").ToList();

// Load one Student and its related enrollments
// using a string to specify the relationship

var student = context.Students
   .Where(s ⇒ s.FirstMidName == "Salman")
   .Include("Enrollments").FirstOrDefault();

หลายระดับ

นอกจากนี้ยังสามารถโหลดเอนทิตีที่เกี่ยวข้องหลายระดับได้อย่างกระตือรือร้น ข้อความค้นหาต่อไปนี้แสดงตัวอย่างของนักเรียนการลงทะเบียนและหลักสูตร

// Load all Students, all related enrollments, and all related courses

var studentList = context.Students
   .Include(s ⇒ s.Enrollments.Select(c ⇒ c.Course)).ToList();

// Load all Students, all related enrollments, and all related courses
// using a string to specify the relationships

var students = context.Students
   .Include("Enrollments.Course").ToList();

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

การโหลดแบบขี้เกียจเป็นกระบวนการที่เอนทิตีหรือคอลเลกชันของเอนทิตีถูกโหลดโดยอัตโนมัติจากฐานข้อมูลในครั้งแรกที่มีการเข้าถึงคุณสมบัติที่อ้างถึงเอนทิตี / เอนทิตี การโหลดอย่างขี้เกียจหมายถึงการโหลดข้อมูลที่เกี่ยวข้องล่าช้าจนกว่าคุณจะร้องขอโดยเฉพาะ

  • เมื่อใช้ชนิดเอนทิตี POCO การโหลดแบบขี้เกียจทำได้โดยการสร้างอินสแตนซ์ของประเภทพร็อกซีที่ได้รับจากนั้นแทนที่คุณสมบัติเสมือนเพื่อเพิ่มเบ็ดการโหลด

  • การโหลดขี้เกียจเป็นค่าเริ่มต้นค่อนข้างมาก

  • หากคุณออกจากการกำหนดค่าเริ่มต้นและไม่ได้บอก Entity Framework อย่างชัดเจนในแบบสอบถามของคุณว่าคุณต้องการอย่างอื่นนอกเหนือจากการโหลดแบบขี้เกียจการโหลดแบบขี้เกียจคือสิ่งที่คุณจะได้รับ

  • ตัวอย่างเช่นเมื่อใช้คลาสเอนทิตี Student การลงทะเบียนที่เกี่ยวข้องจะถูกโหลดในครั้งแรกที่เข้าถึงคุณสมบัติการนำทางการลงทะเบียน

  • คุณสมบัติการนำทางควรกำหนดเป็นสาธารณะเสมือน บริบทจะNOT ขี้เกียจโหลดถ้าคุณสมบัติไม่ได้กำหนดเป็นเสมือน

ต่อไปนี้เป็นชั้นเรียนนักเรียนที่มีคุณสมบัติการนำทางของการลงทะเบียน

public partial class Student {

   public Student() {
      this.Enrollments = new HashSet<Enrollment>();
   }
	
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public System.DateTime EnrollmentDate { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

มาดูตัวอย่างง่ายๆในการโหลดรายชื่อนักเรียนจากฐานข้อมูลก่อนจากนั้นจะโหลดการลงทะเบียนของนักเรียนคนใดคนหนึ่งเมื่อใดก็ตามที่คุณต้องการ

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         //Loading students only
         IList<Student> students = context.Students.ToList<Student>();

         foreach (var student in students) {

            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
	
            foreach (var enrollment in student.Enrollments) {
               Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
                  enrollment.EnrollmentID, enrollment.CourseID);
            }
         }

         Console.ReadKey();
      }
   }
}

เมื่อโค้ดด้านบนถูกคอมไพล์และดำเนินการคุณจะได้รับผลลัพธ์ต่อไปนี้

ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
ID: 2, Name: Meredith Alonso
       Enrollment ID: 4, Course ID: 1045
       Enrollment ID: 5, Course ID: 3141
       Enrollment ID: 6, Course ID: 2021
ID: 3, Name: Arturo Anand
       Enrollment ID: 7, Course ID: 1050
ID: 4, Name: Gytis Barzdukas
       Enrollment ID: 8, Course ID: 1050
       Enrollment ID: 9, Course ID: 4022
ID: 5, Name: Yan Li
       Enrollment ID: 10, Course ID: 4041
ID: 6, Name: Peggy Justice
       Enrollment ID: 11, Course ID: 1045
ID: 7, Name: Laura Norman
       Enrollment ID: 12, Course ID: 3141

ปิด Lazy Loading

การโหลดแบบขี้เกียจและการทำให้เป็นอนุกรมไม่สามารถผสมกันได้และหากคุณไม่ระมัดระวังคุณสามารถค้นหาฐานข้อมูลทั้งหมดของคุณได้เพียงเพราะเปิดใช้งานการโหลดแบบขี้เกียจ เป็นแนวทางปฏิบัติที่ดีในการปิดการโหลดแบบเกียจคร้านก่อนที่คุณจะจัดลำดับเอนทิตี

การปิดสำหรับคุณสมบัติการนำทางเฉพาะ

สามารถปิดการโหลดคอลเล็กชันการลงทะเบียนได้โดยการทำให้คุณสมบัติการลงทะเบียนไม่เสมือนจริงดังที่แสดงในตัวอย่างต่อไปนี้

public partial class Student { 

   public Student() { 
      this.Enrollments = new HashSet<Enrollment>(); 
   }
	
   public int ID { get; set; } 
   public string LastName { get; set; } 
   public string FirstMidName { get; set; } 
   public System.DateTime EnrollmentDate { get; set; }
   public ICollection<Enrollment> Enrollments { get; set; } 
}

ปิดสำหรับเอนทิตีทั้งหมด

Lazy loading สามารถปิดได้สำหรับเอนทิตีทั้งหมดในบริบทโดยตั้งค่าแฟล็กบนคุณสมบัติ Configuration เป็น false ดังที่แสดงในตัวอย่างต่อไปนี้

public partial class UniContextEntities : DbContext { 

   public UniContextEntities(): base("name=UniContextEntities") {
      this.Configuration.LazyLoadingEnabled = false;
   }
	
   protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
      throw new UnintentionalCodeFirstException(); 
   } 
}

หลังจากปิดการโหลดแบบขี้เกียจตอนนี้เมื่อคุณเรียกใช้ตัวอย่างด้านบนอีกครั้งคุณจะเห็นว่าการลงทะเบียนไม่ได้โหลดและดึงเฉพาะข้อมูลนักเรียนเท่านั้น

ID: 1, Name: Ali Alexander
ID: 2, Name: Meredith Alons
ID: 3, Name: Arturo Anand
ID: 4, Name: Gytis Barzduka
ID: 5, Name: Yan Li
ID: 6, Name: Peggy Justice
ID: 7, Name: Laura Norman
ID: 8, Name: Nino Olivetto

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

เมื่อคุณปิดใช้งานการโหลดแบบขี้เกียจคุณยังคงสามารถโหลดเอนทิตีที่เกี่ยวข้องได้อย่างเฉื่อยชา แต่ต้องดำเนินการด้วยการเรียกที่ชัดเจน

  • ซึ่งแตกต่างจากการโหลดแบบขี้เกียจไม่มีความคลุมเครือหรือความสับสนเกี่ยวกับเวลาที่เรียกใช้แบบสอบถาม

  • ในการดำเนินการดังกล่าวให้คุณใช้วิธีการโหลดในรายการของเอนทิตีที่เกี่ยวข้อง

  • สำหรับความสัมพันธ์แบบหนึ่งต่อกลุ่มเรียกใช้วิธีการโหลดบนคอลเล็กชัน

  • และสำหรับความสัมพันธ์แบบหนึ่งต่อกลุ่มให้เรียกใช้เมธอด Load ใน Reference

ลองมาดูตัวอย่างต่อไปนี้ซึ่งปิดใช้งานการโหลดแบบขี้เกียจแล้วนักเรียนที่มีชื่ออาลีจะถูกดึงออกมา

จากนั้นข้อมูลนักเรียนจะถูกเขียนบนคอนโซล หากคุณดูรหัสข้อมูลการลงทะเบียนจะถูกเขียนด้วย แต่เอนทิตีการลงทะเบียนยังไม่ได้โหลดดังนั้น foreach loop จะไม่ถูกดำเนินการ

หลังจากนั้นเอนทิตีการลงทะเบียนจะถูกโหลดอย่างชัดเจนในขณะนี้ข้อมูลของนักเรียนและข้อมูลการลงทะเบียนจะถูกเขียนบนหน้าต่างคอนโซล

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Configuration.LazyLoadingEnabled = false;

         var student = (from s in context.Students where s.FirstMidName == 
            "Ali" select s).FirstOrDefault<Student>();

         string name = student.FirstMidName + " " + student.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
               enrollment.EnrollmentID, enrollment.CourseID);
         }

         Console.WriteLine();
         Console.WriteLine("Explicitly loaded Enrollments");
         Console.WriteLine();

         context.Entry(student).Collection(s ⇒ s.Enrollments).Load();
         Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
               enrollment.EnrollmentID, enrollment.CourseID);
         }

         Console.ReadKey();
      }
   }
}

เมื่อดำเนินการตามตัวอย่างข้างต้นคุณจะได้รับผลลัพธ์ต่อไปนี้ ข้อมูลนักเรียนอันดับแรกเท่านั้นที่จะปรากฏขึ้นและหลังจากโหลดเอนทิตีการลงทะเบียนอย่างชัดเจนทั้งข้อมูลนักเรียนและข้อมูลการลงทะเบียนที่เกี่ยวข้องจะปรากฏขึ้น

ID: 1, Name: Ali Alexander
Explicitly loaded Enrollments
ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ในบทนี้ให้เราเรียนรู้เกี่ยวกับเทคนิคการตรวจสอบความถูกต้องที่สามารถใช้ใน ADO.NET Entity Framework เพื่อตรวจสอบความถูกต้องของข้อมูลแบบจำลอง Entity Framework มีคุณลักษณะการตรวจสอบความถูกต้องที่หลากหลายซึ่งสามารถนำไปใช้กับส่วนติดต่อผู้ใช้สำหรับการตรวจสอบความถูกต้องฝั่งไคลเอ็นต์หรือสามารถใช้สำหรับการตรวจสอบความถูกต้องทางฝั่งเซิร์ฟเวอร์

  • ใน Entity Framework การตรวจสอบข้อมูลเป็นส่วนหนึ่งของโซลูชันสำหรับการดักจับข้อมูลที่ไม่ดีในแอปพลิเคชัน

  • Entity Framework ตรวจสอบความถูกต้องของข้อมูลทั้งหมดก่อนที่จะเขียนลงในฐานข้อมูลโดยค่าเริ่มต้นโดยใช้วิธีการตรวจสอบข้อมูลที่หลากหลาย

  • อย่างไรก็ตาม Entity Framework มาหลังจากการตรวจสอบข้อมูลอินเทอร์เฟซผู้ใช้ ดังนั้นในกรณีนี้จำเป็นต้องมีการตรวจสอบเอนทิตีเพื่อจัดการกับข้อยกเว้นใด ๆ ที่ EF พ่นและแสดงข้อความทั่วไป

  • มีเทคนิคบางอย่างในการตรวจสอบข้อมูลเพื่อปรับปรุงการตรวจสอบข้อผิดพลาดและวิธีส่งข้อความแสดงข้อผิดพลาดกลับไปยังผู้ใช้

DbContext มีเมธอด Overridable ที่เรียกว่า ValidateEntity เมื่อคุณเรียกใช้ SaveChanges Entity Framework จะเรียกเมธอดนี้สำหรับแต่ละเอนทิตีในแคชที่มีสถานะไม่เปลี่ยนแปลง คุณสามารถใส่ตรรกะการตรวจสอบได้โดยตรงที่นี่ดังที่แสดงในตัวอย่างต่อไปนี้สำหรับเอนทิตีนักเรียน

public partial class UniContextEntities : DbContext {

   protected override System.Data.Entity.Validation
      .DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, 
      System.Collections.Generic.IDictionary<object, object> items) {

         if (entityEntry.Entity is Student) {

            if (entityEntry.CurrentValues.GetValue<string>("FirstMidName") == "") {

               var list = new List<System.Data.Entity
                  .Validation.DbValidationError>();

               list.Add(new System.Data.Entity.Validation
                  .DbValidationError("FirstMidName", "FirstMidName is required"));

               return new System.Data.Entity.Validation
                  .DbEntityValidationResult(entityEntry, list);
            }
         }

         if (entityEntry.CurrentValues.GetValue<string>("LastName") == "") {

            var list = new List<System.Data.Entity
               .Validation.DbValidationError>();

            list.Add(new System.Data.Entity.Validation
               .DbValidationError("LastName", "LastName is required"));

            return new System.Data.Entity.Validation
               .DbEntityValidationResult(entityEntry, list);
         }

         return base.ValidateEntity(entityEntry, items);
   }
}

ในวิธีการ ValidateEntity ข้างต้นคุณสมบัติ Student entity FirstMidName และ LastName จะถูกตรวจสอบหากคุณสมบัติใด ๆ เหล่านี้มีสตริงว่างจากนั้นจะส่งคืนข้อความแสดงข้อผิดพลาด

ลองมาดูตัวอย่างง่ายๆที่นักเรียนใหม่ถูกสร้างขึ้น แต่ FirstMidName ของนักเรียนเป็นสตริงว่างดังที่แสดงในโค้ดต่อไปนี้

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         Console.WriteLine("Adding new Student to the database");
         Console.WriteLine();

         try {

            context.Students.Add(new Student() {
               FirstMidName = "",
               LastName = "Upston"
            });

            context.SaveChanges();
         } catch (DbEntityValidationException dbValidationEx) {

            foreach (DbEntityValidationResult entityErr in 
               dbValidationEx.EntityValidationErrors) {

               foreach (DbValidationError error in entityErr.ValidationErrors) {
                  Console.WriteLine("Error: {0}",error.ErrorMessage);
               }
            }
         }

         Console.ReadKey();
      }
   }
}

เมื่อตัวอย่างด้านบนถูกคอมไพล์และดำเนินการคุณจะได้รับข้อความแสดงข้อผิดพลาดต่อไปนี้บนหน้าต่างคอนโซล

Adding new Student to the database  
Error: FirstMidName is required

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

Entity Framework ให้ความสามารถในการติดตามการเปลี่ยนแปลงที่เกิดขึ้นกับเอนทิตีและความสัมพันธ์ของพวกเขาดังนั้นการอัปเดตที่ถูกต้องจะทำบนฐานข้อมูลเมื่อมีการเรียกวิธีการ SaveChanges ของบริบท นี่คือคุณสมบัติหลักของ Entity Framework

  • การติดตามการเปลี่ยนแปลงจะติดตามการเปลี่ยนแปลงในขณะที่เพิ่มเรกคอร์ดใหม่ในคอลเล็กชันเอนทิตีแก้ไขหรือลบเอนทิตีที่มีอยู่

  • จากนั้นการเปลี่ยนแปลงทั้งหมดจะถูกเก็บไว้โดยระดับ DbContext

  • การเปลี่ยนแปลงแทร็กเหล่านี้จะหายไปหากไม่ได้บันทึกไว้ก่อนที่วัตถุ DbContext จะถูกทำลาย

  • คลาส DbChangeTracker ให้ข้อมูลทั้งหมดเกี่ยวกับเอนทิตีปัจจุบันที่ถูกติดตามโดยบริบท

  • ในการติดตามเอนทิตีตามบริบทนั้นจะต้องมีคุณสมบัติคีย์หลัก

ใน Entity Framework การติดตามการเปลี่ยนแปลงจะเปิดใช้งานโดยค่าเริ่มต้น คุณยังสามารถปิดใช้งานการติดตามการเปลี่ยนแปลงได้โดยตั้งค่าคุณสมบัติ AutoDetectChangesEnabled ของ DbContext เป็น false ถ้าคุณสมบัตินี้ถูกตั้งค่าเป็น true ดังนั้น Entity Framework จะรักษาสถานะของเอนทิตี

using (var context = new UniContextEntities()) {
   context.Configuration.AutoDetectChangesEnabled = true;
}

ลองมาดูตัวอย่างต่อไปนี้ซึ่งนักเรียนและการลงทะเบียนของพวกเขาถูกดึงมาจากฐานข้อมูล

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Configuration.AutoDetectChangesEnabled = true;
         Console.WriteLine("Retrieve Student");

         var student = (from s in context.Students where s.FirstMidName == 
            "Ali" select s).FirstOrDefault<Student>();

         string name = student.FirstMidName + " " + student.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
         Console.WriteLine();
         Console.WriteLine("Retrieve all related enrollments");

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
               enrollment.EnrollmentID, enrollment.CourseID);
         }

         Console.WriteLine();

         Console.WriteLine("Context tracking changes of {0} entity.", 
            context.ChangeTracker.Entries().Count());

         var entries = context.ChangeTracker.Entries();

         foreach (var entry in entries) {
            Console.WriteLine("Entity Name: {0}", entry.Entity.GetType().Name);
            Console.WriteLine("Status: {0}", entry.State);
         }

         Console.ReadKey();
      }
   }
}

เมื่อรวบรวมและดำเนินการตัวอย่างข้างต้นคุณจะได้รับผลลัพธ์ต่อไปนี้

Retrieve Student 
ID: 1, Name: Ali Alexander
Retrieve all related enrollments
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
Context tracking changes of 4 entity.
Entity Name: Student
Status: Unchanged
Entity Name: Enrollment
Status: Unchanged
Entity Name: Enrollment
Status: Unchanged
Entity Name: Enrollment
Status: Unchanged

คุณจะเห็นว่าข้อมูลทั้งหมดถูกดึงมาจากฐานข้อมูลเท่านั้นนั่นคือสาเหตุที่สถานะไม่เปลี่ยนแปลงสำหรับเอนทิตีทั้งหมด

ตอนนี้เรามาดูตัวอย่างง่ายๆอีกตัวอย่างหนึ่งซึ่งเราจะเพิ่มการลงทะเบียนอีกหนึ่งรายการและลบนักเรียนหนึ่งคนออกจากฐานข้อมูล ต่อไปนี้เป็นรหัสที่เพิ่มการลงทะเบียนใหม่และนักเรียนหนึ่งคนถูกลบ

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Configuration.AutoDetectChangesEnabled = true;

         Enrollment enr = new Enrollment() { 
            StudentID = 1, CourseID = 3141 
         };

         Console.WriteLine("Adding New Enrollment");
         context.Enrollments.Add(enr);
         Console.WriteLine("Delete Student");

         var student = (from s in context.Students where s.ID == 
            23 select s).SingleOrDefault<Student>();

         context.Students.Remove(student);
         Console.WriteLine("");

         Console.WriteLine("Context tracking changes of {0} entity.", 
            context.ChangeTracker.Entries().Count());
         var entries = context.ChangeTracker.Entries();

         foreach (var entry in entries) {
            Console.WriteLine("Entity Name: {0}", entry.Entity.GetType().Name);
            Console.WriteLine("Status: {0}", entry.State);
         }

         Console.ReadKey();
      }
   }
}

เมื่อรวบรวมและดำเนินการตัวอย่างข้างต้นคุณจะได้รับผลลัพธ์ต่อไปนี้

Adding New Enrollment
Delete Student
Context tracking changes of 2 entity.
Entity Name: Enrollment
Status: Added
Entity Name: Student
Status: Deleted

ตอนนี้คุณจะเห็นได้ว่าสถานะของเอนทิตีการลงทะเบียนถูกตั้งค่าเป็นเพิ่มและสถานะของเอนทิตีนักเรียนจะถูกลบเนื่องจากมีการเพิ่มการลงทะเบียนใหม่และนักเรียนหนึ่งคนถูกลบออกจากฐานข้อมูล

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ในเอนทิตีกรอบงานเอนทิตีสีส่วนใหญ่เกี่ยวกับการเปลี่ยนสีของเอนทิตีในตัวออกแบบเพื่อให้นักพัฒนาสามารถระบุกลุ่มของเอนทิตีที่เกี่ยวข้องในตัวออกแบบ Visual Studio ได้ง่าย ฟีเจอร์นี้เปิดตัวครั้งแรกใน Entity Framework 5.0

  • คุณลักษณะนี้ไม่มีส่วนเกี่ยวข้องกับด้านประสิทธิภาพ

  • เมื่อคุณมีโปรเจ็กต์ขนาดใหญ่และเอนทิตีจำนวนมากในไฟล์ edmx เดียวฟีเจอร์นี้จะมีประโยชน์มากในการแยกเอนทิตีของคุณในโมดูลต่างๆ

หากคุณกำลังทำงานกับไฟล์ edmx และคุณได้เปิดในตัวออกแบบหากต้องการเปลี่ยนสีให้เลือกเอนทิตีบนหน้าต่างออกแบบ จากนั้นคลิกขวาและเลือก Properties

ในหน้าต่างคุณสมบัติเลือกคุณสมบัติเติมสี

ระบุสีโดยใช้ชื่อสีที่ถูกต้องเช่นสีเขียวหรือ RGB ที่ถูกต้อง (255, 128, 128) หรือคุณยังสามารถเลือกจากตัวเลือกสี

หากต้องการเปลี่ยนสีของหลายเอนทิตีในครั้งเดียวให้เลือกหลายเอนทิตีและเปลี่ยนสีเติมสำหรับเอนทิตีทั้งหมดโดยใช้หน้าต่างคุณสมบัติ

คุณยังสามารถเปลี่ยนรูปแบบของคุณสมบัติโดยเลือกตัวเลือกใด ๆ ต่อไปนี้ -

  • ชื่อที่แสดง
  • ชื่อและประเภทที่ปรากฏ

โดยค่าเริ่มต้นตัวเลือกชื่อที่แสดงจะถูกเลือก หากต้องการเปลี่ยนรูปแบบคุณสมบัติให้คลิกขวาที่หน้าต่างตัวออกแบบ

เลือกรูปแบบคุณสมบัติ Scalar →ชื่อที่แสดงและประเภท

ตอนนี้คุณจะเห็นว่าประเภทนั้นแสดงพร้อมกับชื่อด้วย

Entity Framework มีสามแนวทางในการสร้างแบบจำลองเอนทิตีและแต่ละวิธีมีข้อดีและข้อเสียของตนเอง

  • รหัสแรก
  • ฐานข้อมูลก่อน
  • รุ่นแรก

ในบทนี้เราจะอธิบายสั้น ๆ เกี่ยวกับแนวทางแรกของรหัส นักพัฒนาบางคนชอบที่จะทำงานร่วมกับ Designer ใน Code ในขณะที่บางคนต้องการทำงานกับ Code ของตนเท่านั้น สำหรับนักพัฒนาเหล่านั้น Entity Framework มีเวิร์กโฟลว์การสร้างแบบจำลองที่เรียกว่า Code First

  • เวิร์กโฟลว์การสร้างโมเดล Code First กำหนดเป้าหมายฐานข้อมูลที่ไม่มีอยู่และ Code First จะสร้างขึ้น

  • นอกจากนี้ยังสามารถใช้ได้หากคุณมีฐานข้อมูลว่างจากนั้น Code First จะเพิ่มตารางใหม่เข้าไป

  • Code First ช่วยให้คุณกำหนดโมเดลของคุณโดยใช้คลาส C # หรือ VB.Net

  • การกำหนดค่าเพิ่มเติมสามารถเลือกดำเนินการได้โดยใช้แอตทริบิวต์ในคลาสและคุณสมบัติของคุณหรือใช้ API ที่คล่องแคล่ว

ทำไมต้องเป็นรหัสแรก

  • Code First สร้างขึ้นจากชุดตัวต่อ อันดับแรกคือคลาสโดเมนของคุณ

  • คลาสโดเมนไม่มีส่วนเกี่ยวข้องกับ Entity Framework เป็นเพียงรายการในโดเมนธุรกิจของคุณ

  • ดังนั้น Entity Framework จะมีบริบทที่จัดการปฏิสัมพันธ์ระหว่างคลาสเหล่านั้นกับฐานข้อมูลของคุณ

  • บริบทไม่เฉพาะเจาะจงสำหรับ Code First เป็นคุณสมบัติของ Entity Framework

  • Code First เพิ่มตัวสร้างโมเดลที่ตรวจสอบคลาสของคุณว่าบริบทกำลังจัดการจากนั้นใช้ชุดของกฎหรืออนุสัญญาเพื่อกำหนดว่าคลาสเหล่านั้นและความสัมพันธ์อธิบายโมเดลอย่างไรและโมเดลนั้นควรแมปกับฐานข้อมูลของคุณอย่างไร

  • ทั้งหมดนี้เกิดขึ้นที่รันไทม์ คุณจะไม่เห็นโมเดลนี้ แต่อยู่ในความทรงจำ

  • Code First ยังมีความสามารถในการใช้โมเดลนั้นเพื่อสร้างฐานข้อมูลหากคุณต้องการ

  • นอกจากนี้ยังสามารถอัปเดตฐานข้อมูลหากโมเดลเปลี่ยนแปลงโดยใช้คุณลักษณะที่เรียกว่า Code First Migrations

การตั้งค่าสภาพแวดล้อม

ในการเริ่มต้นทำงานกับแนวทาง EF Code First คุณต้องติดตั้งเครื่องมือต่อไปนี้ในระบบของคุณ

  • Visual Studio 2013 (.net framework 4.5.2) หรือเวอร์ชันที่ใหม่กว่า
  • MS SQL Server 2012 หรือใหม่กว่า
  • Entity Framework ผ่าน NuGet Package

ติดตั้ง EF ผ่าน NuGet Package

Step 1 - ขั้นแรกให้สร้างแอปพลิเคชันคอนโซลจากไฟล์→ใหม่→โครงการ ...

Step 2 - เลือก Windows จากบานหน้าต่างด้านซ้ายและแอปพลิเคชันคอนโซลจากบานหน้าต่างเทมเพลต

Step 3 - ป้อน EFCodeFirstDemo เป็นชื่อและเลือกตกลง

Step 4 - คลิกขวาที่โครงการของคุณในตัวสำรวจโซลูชันและเลือกจัดการ NuGet Packages ...

เพื่อเปิด NuGet Package Manager และค้นหา EntityFramework เพื่อค้นหาแพ็คเกจทั้งหมดที่เกี่ยวข้องกับ Entity Framework

Step 5- เลือก EntityFramework และคลิกที่ติดตั้ง หรือจากเมนู Tools คลิก NuGet Package Manager จากนั้นคลิก Package Manager Console ในหน้าต่าง Package Manager Console ให้ป้อนคำสั่งต่อไปนี้: Install-Package EntityFramework

เมื่อการติดตั้งเสร็จสมบูรณ์คุณจะเห็นข้อความต่อไปนี้ในหน้าต่างผลลัพธ์“ ติดตั้งเรียบร้อยแล้ว 'EntityFramework 6.1.2' ไปยัง EFCodeFirstDemo”

หลังการติดตั้ง EntityFramework.dll จะรวมอยู่ในโครงการของคุณดังที่แสดงในภาพต่อไปนี้

ตอนนี้คุณพร้อมที่จะเริ่มทำงานกับแนวทาง Code First แล้ว

มากำหนดโมเดลง่ายๆโดยใช้คลาส เรากำลังกำหนดสิ่งเหล่านี้ในไฟล์ 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; }
}

DataAnnotations ใช้เพื่อกำหนดค่าคลาสซึ่งจะเน้นการกำหนดค่าที่จำเป็นโดยทั่วไป นอกจากนี้ DataAnnotations ยังเข้าใจโดยแอปพลิเคชัน. NET จำนวนมากเช่น ASP.NET MVC ซึ่งช่วยให้แอปพลิเคชันเหล่านี้ใช้ประโยชน์จากคำอธิบายประกอบเดียวกันสำหรับการตรวจสอบความถูกต้องฝั่งไคลเอ็นต์ แอตทริบิวต์ DataAnnotation แทนที่อนุสัญญา CodeFirst เริ่มต้น

System.ComponentModel.DataAnnotations มีแอตทริบิวต์ต่อไปนี้ที่ส่งผลต่อความเป็นโมฆะหรือขนาดของคอลัมน์

  • Key
  • Timestamp
  • ConcurrencyCheck
  • Required
  • MinLength
  • MaxLength
  • StringLength

System.ComponentModel.DataAnnotations.Schema เนมสเปซประกอบด้วยแอ็ตทริบิวต์ต่อไปนี้ที่มีผลต่อสคีมาของฐานข้อมูล

  • Table
  • Column
  • Index
  • ForeignKey
  • NotMapped
  • InverseProperty

สำคัญ

Entity Framework อาศัยทุกเอนทิตีที่มีค่าคีย์ที่ใช้สำหรับการติดตามเอนทิตี หนึ่งในอนุสัญญาที่ Code First ขึ้นอยู่กับว่ามันบอกเป็นนัยว่าคุณสมบัติใดเป็นกุญแจสำคัญในแต่ละคลาสของ Code First

  • Convention คือการมองหาคุณสมบัติชื่อ“ Id” หรือคุณสมบัติที่รวมชื่อคลาสและ“ Id” เช่น“ StudentId”

  • คุณสมบัติจะแมปกับคอลัมน์คีย์หลักในฐานข้อมูล

  • ชั้นเรียนนักศึกษาหลักสูตรและการลงทะเบียนเป็นไปตามอนุสัญญานี้

ตอนนี้สมมติว่าคลาสนักเรียนใช้ชื่อ StdntID แทน ID เมื่อ Code First ไม่พบคุณสมบัติที่ตรงกับข้อตกลงนี้จะทำให้เกิดข้อยกเว้นเนื่องจากข้อกำหนดของ Entity Framework ที่คุณต้องมีคุณสมบัติหลัก คุณสามารถใช้คำอธิบายประกอบคีย์เพื่อระบุคุณสมบัติที่จะใช้เป็น EntityKey

ลองดูรหัสต่อไปนี้ของชั้นเรียนนักเรียนซึ่งมี StdntID แต่ไม่เป็นไปตามหลักการเริ่มต้นของ Code First ดังนั้นเพื่อจัดการกับสิ่งนี้จึงมีการเพิ่มแอตทริบิวต์ของคีย์ซึ่งจะทำให้เป็นคีย์หลัก

public class Student {

   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

เมื่อคุณเรียกใช้แอปพลิเคชันของคุณและตรวจสอบฐานข้อมูลของคุณใน SQL Server Explorer คุณจะเห็นว่าขณะนี้คีย์หลักคือ StdntID ในตารางนักเรียน

Entity Framework ยังรองรับคีย์คอมโพสิต Composite keysยังเป็นคีย์หลักที่ประกอบด้วยคุณสมบัติมากกว่าหนึ่งรายการ ตัวอย่างเช่นคุณมีคลาส DrivingLicense ซึ่งมีคีย์หลักเป็นชุดของ LicenseNumber และ IssuingCountry

public class DrivingLicense {

   [Key, Column(Order = 1)]
   public int LicenseNumber { get; set; }
   [Key, Column(Order = 2)]
   public string IssuingCountry { get; set; }
   public DateTime Issued { get; set; }
   public DateTime Expires { get; set; }
}

เมื่อคุณมีคีย์ผสม Entity Framework ต้องการให้คุณกำหนดลำดับคุณสมบัติของคีย์ คุณสามารถทำได้โดยใช้คำอธิบายประกอบคอลัมน์เพื่อระบุคำสั่งซื้อ

การประทับเวลา

Code First จะปฏิบัติต่อคุณสมบัติ Timestamp เช่นเดียวกับคุณสมบัติ ConcurrencyCheck แต่ยังช่วยให้แน่ใจว่าฟิลด์ฐานข้อมูลที่โค้ดสร้างขึ้นเป็นครั้งแรกไม่เป็นค่าว่าง

  • เป็นเรื่องปกติมากขึ้นที่จะใช้เขตข้อมูล rowversion หรือ timestamp สำหรับการตรวจสอบการทำงานพร้อมกัน

  • แทนที่จะใช้คำอธิบายประกอบ ConcurrencyCheck คุณสามารถใช้คำอธิบายประกอบ TimeStamp ที่เฉพาะเจาะจงมากขึ้นได้ตราบเท่าที่ชนิดของคุณสมบัติเป็นไบต์อาร์เรย์

  • คุณสามารถมีคุณสมบัติการประทับเวลาได้เพียงหนึ่งรายการในคลาสที่กำหนด

มาดูตัวอย่างง่ายๆโดยการเพิ่มคุณสมบัติ TimeStamp ในคลาส Course -

public class Course {

   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
   [Timestamp]
   public byte[] TStamp { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ดังที่คุณเห็นในตัวอย่างข้างต้นแอตทริบิวต์ Timestamp ถูกนำไปใช้กับคุณสมบัติ Byte [] ของคลาสหลักสูตร ดังนั้น Code First จะสร้างคอลัมน์การประทับเวลาTStampในตารางหลักสูตร

การทำงานพร้อมกันตรวจสอบ

คำอธิบายประกอบ ConcurrencyCheck อนุญาตให้คุณตั้งค่าสถานะคุณสมบัติอย่างน้อยหนึ่งรายการเพื่อใช้สำหรับการตรวจสอบพร้อมกันในฐานข้อมูลเมื่อผู้ใช้แก้ไขหรือลบเอนทิตี หากคุณเคยทำงานกับ EF Designer สิ่งนี้จะสอดคล้องกับการตั้งค่า ConcurrencyMode ของคุณสมบัติเป็นคงที่

ลองมาดูตัวอย่างง่ายๆของการทำงานของ ConcurrencyCheck โดยการเพิ่มเข้าไปในคุณสมบัติ Title ในคลาส Course

public class Course {

   public int CourseID { get; set; }
   [ConcurrencyCheck]
   public string Title { get; set; }
   public int Credits { get; set; }
   [Timestamp, DataType("timestamp")]
   public byte[] TimeStamp { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ในชั้นเรียนหลักสูตรข้างต้นแอตทริบิวต์ ConcurrencyCheck ถูกนำไปใช้กับคุณสมบัติ Title ที่มีอยู่ ตอนนี้ Code First จะรวมคอลัมน์ Title ไว้ในคำสั่ง update เพื่อตรวจสอบการเกิดพร้อมกันในแง่ดีดังที่แสดงในโค้ดต่อไปนี้

exec sp_executesql N'UPDATE [dbo].[Courses]
   SET [Title] = @0
   WHERE (([CourseID] = @1) AND ([Title] = @2))
   ',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'Maths',@1=1,@2=N'Calculus'
go

คำอธิบายประกอบที่จำเป็น

คำอธิบายประกอบที่จำเป็นจะบอก EF ว่าจำเป็นต้องมีคุณสมบัติเฉพาะ มาดูคลาสนักเรียนต่อไปนี้ซึ่งไอดีที่ต้องการถูกเพิ่มเข้าไปในคุณสมบัติ FirstMidName แอตทริบิวต์ที่จำเป็นจะบังคับให้ EF ต้องแน่ใจว่าคุณสมบัตินั้นมีข้อมูลอยู่

public class Student {

   [Key]
   public int StdntID { get; set; }

   [Required]
   public string LastName { get; set; }

   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ดังที่เห็นในตัวอย่างข้างต้นแอตทริบิวต์ที่จำเป็นถูกนำไปใช้กับ FirstMidName และ LastName ดังนั้น Code First จะสร้างคอลัมน์ NOT NULL FirstMidName และ LastName ในตาราง Students ดังที่แสดงในภาพต่อไปนี้

MaxLength

แอตทริบิวต์ MaxLength ช่วยให้คุณระบุการตรวจสอบคุณสมบัติเพิ่มเติม สามารถนำไปใช้กับคุณสมบัติประเภทสตริงหรืออาร์เรย์ของคลาสโดเมน EF Code First จะกำหนดขนาดของคอลัมน์ตามที่ระบุในแอตทริบิวต์ MaxLength

มาดูคลาสหลักสูตรต่อไปนี้ซึ่งใช้แอตทริบิวต์ MaxLength (24) กับคุณสมบัติ Title

public class Course {

   public int CourseID { get; set; }
   [ConcurrencyCheck]
   [MaxLength(24)]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

เมื่อคุณเรียกใช้แอปพลิเคชันข้างต้น Code First จะสร้างชื่อคอลัมน์ nvarchar (24) ในตาราง CourseId ดังที่แสดงในภาพต่อไปนี้

เมื่อผู้ใช้ตั้งค่า Title ซึ่งมีอักขระมากกว่า 24 ตัว EF จะโยน EntityValidationError

MinLength

แอตทริบิวต์ MinLength ยังช่วยให้คุณสามารถระบุการตรวจสอบคุณสมบัติเพิ่มเติมได้เช่นเดียวกับที่คุณทำกับ MaxLength นอกจากนี้ยังสามารถใช้แอตทริบิวต์ MinLength กับแอตทริบิวต์ MaxLength ดังที่แสดงในรหัสต่อไปนี้

public class Course {

   public int CourseID { get; set; }
   [ConcurrencyCheck]
   [MaxLength(24) , MinLength(5)]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

EF จะโยน EntityValidationError ถ้าคุณตั้งค่าคุณสมบัติ Title น้อยกว่าความยาวที่ระบุในแอตทริบิวต์ MinLength หรือมากกว่าความยาวที่ระบุในแอตทริบิวต์ MaxLength

StringLength

StringLength ยังช่วยให้คุณระบุการตรวจสอบคุณสมบัติเพิ่มเติมเช่น MaxLength ข้อแตกต่างเพียงอย่างเดียวคือแอตทริบิวต์ StringLength สามารถใช้ได้กับคุณสมบัติประเภทสตริงของคลาสโดเมนเท่านั้น

public class Course {

   public int CourseID { get; set; }
   [StringLength (24)]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Entity Framework ยังตรวจสอบค่าของคุณสมบัติสำหรับแอตทริบิวต์ StringLength หากผู้ใช้ตั้งค่า Title ซึ่งมีอักขระมากกว่า 24 ตัว EF จะโยน EntityValidationError

ตาราง

หลักการเริ่มต้นของ Code First สร้างชื่อตารางที่คล้ายกับชื่อคลาส หากคุณปล่อยให้ Code First สร้างฐานข้อมูลและต้องการเปลี่ยนชื่อของตารางที่กำลังสร้าง จากนั้น -

  • คุณสามารถใช้ Code First กับฐานข้อมูลที่มีอยู่ แต่ไม่ใช่ทุกกรณีที่ชื่อของคลาสจะตรงกับชื่อของตารางในฐานข้อมูลของคุณ

  • แอตทริบิวต์ของตารางจะแทนที่แบบแผนเริ่มต้นนี้

  • EF Code First จะสร้างตารางที่มีชื่อที่ระบุในแอตทริบิวต์ Table สำหรับคลาสโดเมนที่กำหนด

ลองมาดูตัวอย่างต่อไปนี้ซึ่งชั้นเรียนมีชื่อว่า Student และตามแบบแผน Code First สันนิษฐานว่าสิ่งนี้จะจับคู่กับตารางที่ชื่อนักเรียน หากไม่เป็นเช่นนั้นคุณสามารถระบุชื่อของตารางด้วยแอตทริบิวต์ Table ดังที่แสดงในรหัสต่อไปนี้

[Table("StudentsInfo")]
public class Student {

   [Key]
   public int StdntID { get; set; }
   [Required]
   public string LastName { get; set; }
   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ตอนนี้คุณจะเห็นว่าแอตทริบิวต์ Table ระบุตารางเป็น StudentsInfo เมื่อสร้างตารางคุณจะเห็นชื่อตาราง StudentsInfo ดังแสดงในภาพต่อไปนี้

คุณไม่สามารถระบุชื่อตารางเท่านั้น แต่คุณสามารถระบุสคีมาสำหรับตารางโดยใช้แอตทริบิวต์ Table ดังที่แสดงในโค้ดต่อไปนี้

[Table("StudentsInfo", Schema = "Admin")] 
public class Student {

   [Key]
   public int StdntID { get; set; }
   [Required]
   public string LastName { get; set; }
   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

คุณสามารถดูในตัวอย่างด้านบนตารางถูกระบุด้วยสคีมาของผู้ดูแลระบบ ตอนนี้ Code First จะสร้างตาราง StudentsInfo ใน Admin schema ดังที่แสดงในภาพต่อไปนี้

คอลัมน์

นอกจากนี้ยังเหมือนกับแอตทริบิวต์ Table แต่แอตทริบิวต์ Table จะแทนที่ลักษณะการทำงานของตารางในขณะที่แอตทริบิวต์ Column แทนที่ลักษณะการทำงานของคอลัมน์ หลักการเริ่มต้นของ Code First สร้างชื่อคอลัมน์ที่คล้ายกับชื่อคุณสมบัติ หากคุณปล่อยให้ Code First สร้างฐานข้อมูลและต้องการเปลี่ยนชื่อคอลัมน์ในตารางของคุณด้วย จากนั้น -

  • แอตทริบิวต์คอลัมน์จะแทนที่การประชุมเริ่มต้น

  • EF Code First จะสร้างคอลัมน์ที่มีชื่อที่ระบุในแอตทริบิวต์คอลัมน์สำหรับคุณสมบัติที่กำหนด

ลองดูตัวอย่างต่อไปนี้ซึ่งคุณสมบัตินี้มีชื่อว่า FirstMidName และตามแบบแผน Code First สันนิษฐานว่าสิ่งนี้จะแมปกับคอลัมน์ชื่อ FirstMidName

หากไม่ใช่กรณีนี้คุณสามารถระบุชื่อของคอลัมน์ด้วยแอตทริบิวต์ Column ดังที่แสดงในรหัสต่อไปนี้

public class Student {

   public int ID { get; set; }
   public string LastName { get; set; }
   [Column("FirstName")]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

คุณจะเห็นว่าคอลัมน์แอตทริบิวต์ระบุคอลัมน์เป็น FirstName เมื่อสร้างตารางขึ้นคุณจะเห็นชื่อคอลัมน์ FirstName ดังแสดงในภาพต่อไปนี้

ดัชนี

แอตทริบิวต์ Index ถูกนำมาใช้ใน Entity Framework 6.1 หากคุณใช้เวอร์ชันก่อนหน้านี้ข้อมูลในส่วนนี้จะใช้ไม่ได้

  • คุณสามารถสร้างดัชนีในคอลัมน์อย่างน้อยหนึ่งคอลัมน์โดยใช้ IndexAttribute

  • การเพิ่มแอตทริบิวต์ให้กับคุณสมบัติอย่างน้อยหนึ่งคุณสมบัติจะทำให้ EF สร้างดัชนีที่สอดคล้องกันในฐานข้อมูลเมื่อสร้างฐานข้อมูล

  • ดัชนีทำให้การดึงข้อมูลเร็วขึ้นและมีประสิทธิภาพในกรณีส่วนใหญ่ อย่างไรก็ตามการใส่ตารางหรือมุมมองที่มีดัชนีมากเกินไปอาจส่งผลต่อประสิทธิภาพของการดำเนินการอื่น ๆ เช่นการแทรกหรือการอัปเดต

  • การจัดทำดัชนีเป็นคุณลักษณะใหม่ใน Entity Framework ที่คุณสามารถปรับปรุงประสิทธิภาพของแอปพลิเคชัน Code First ของคุณได้โดยลดเวลาที่ต้องใช้ในการสืบค้นข้อมูลจากฐานข้อมูล

  • คุณสามารถเพิ่มดัชนีให้กับฐานข้อมูลของคุณโดยใช้แอตทริบิวต์ดัชนีและแทนที่ค่าเริ่มต้นที่ไม่ซ้ำกันและการตั้งค่าคลัสเตอร์เพื่อให้ได้ดัชนีที่เหมาะสมกับสถานการณ์ของคุณมากที่สุด

  • ตามค่าเริ่มต้นดัชนีจะถูกตั้งชื่อว่า IX_ <ชื่อคุณสมบัติ>

มาดูโค้ดต่อไปนี้ซึ่งมีการเพิ่มแอตทริบิวต์ดัชนีในคลาสหลักสูตรสำหรับเครดิต

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

คุณจะเห็นว่าแอตทริบิวต์ดัชนีถูกนำไปใช้กับคุณสมบัติเครดิต เมื่อสร้างตารางขึ้นคุณจะเห็น IX_Credits ใน Indexes

โดยค่าเริ่มต้นดัชนีจะไม่ซ้ำกัน แต่คุณสามารถใช้ไฟล์ IsUniqueตั้งชื่อพารามิเตอร์เพื่อระบุว่าดัชนีควรไม่ซ้ำกัน ตัวอย่างต่อไปนี้แนะนำดัชนีเฉพาะดังที่แสดงในโค้ดต่อไปนี้

public class Course {
   public int CourseID { get; set; }
   [Index(IsUnique = true)]
	
   public string Title { get; set; }
   [Index]
	
   public int Credits { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ForeignKey

การประชุม Code First จะดูแลความสัมพันธ์ที่พบบ่อยที่สุดในโมเดลของคุณ แต่มีบางกรณีที่ต้องการความช่วยเหลือ ตัวอย่างเช่นการเปลี่ยนชื่อของคุณสมบัติหลักในคลาสนักเรียนทำให้เกิดปัญหากับความสัมพันธ์กับคลาสการลงทะเบียน

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 {
   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ในขณะที่สร้างฐานข้อมูล Code First จะเห็นคุณสมบัติ StudentID ในคลาสการลงทะเบียนและรับรู้โดยแบบแผนว่าตรงกับชื่อคลาสบวกกับ "ID" เป็นคีย์ต่างประเทศสำหรับคลาส Student อย่างไรก็ตามไม่มีคุณสมบัติ StudentID ในคลาส Student แต่คุณสมบัติ StdntID คือคลาส Student

วิธีแก้ปัญหานี้คือการสร้างคุณสมบัติการนำทางในการลงทะเบียนและใช้ ForeignKey DataAnnotation เพื่อช่วยให้ Code First เข้าใจวิธีสร้างความสัมพันธ์ระหว่างสองคลาสดังที่แสดงในโค้ดต่อไปนี้

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; }
   [ForeignKey("StudentID")]
	
   public virtual Student Student { get; set; }
}

ตอนนี้คุณสามารถเห็นได้ว่าแอตทริบิวต์ ForeignKey ถูกนำไปใช้กับคุณสมบัติการนำทาง

ไม่แมป

ตามมาตรฐานเริ่มต้นของ Code First ทุกคุณสมบัติที่เป็นชนิดข้อมูลที่รองรับและซึ่งรวมถึง getters และ setters จะแสดงในฐานข้อมูล แต่นี่ไม่ใช่กรณีเสมอไปในแอปพลิเคชันของคุณ แอตทริบิวต์ NotMapped แทนที่แบบแผนเริ่มต้นนี้ ตัวอย่างเช่นคุณอาจมีคุณสมบัติในชั้นเรียนนักเรียนเช่น FatherName แต่ไม่จำเป็นต้องจัดเก็บ คุณสามารถใช้แอตทริบิวต์ NotMapped กับคุณสมบัติ FatherName ซึ่งคุณไม่ต้องการสร้างคอลัมน์ในฐานข้อมูลดังที่แสดงในรหัสต่อไปนี้

public class Student {
   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
	
   public DateTime EnrollmentDate { get; set; }
   [NotMapped]

   public int FatherName { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

คุณจะเห็นว่ามีการใช้แอตทริบิวต์ NotMapped กับคุณสมบัติ FatherName เมื่อสร้างตารางคุณจะเห็นว่าคอลัมน์ FatherName จะไม่ถูกสร้างขึ้นในฐานข้อมูล แต่มีอยู่ในชั้นเรียนของนักเรียน

Code First จะไม่สร้างคอลัมน์สำหรับคุณสมบัติซึ่งไม่มี getters หรือ setters ดังที่แสดงในตัวอย่างคุณสมบัติ Address and Age ของคลาส Student ต่อไปนี้

คุณสมบัติผกผัน

InverseProperty ถูกใช้เมื่อคุณมีหลายความสัมพันธ์ระหว่างคลาส ในชั้นเรียนการลงทะเบียนคุณอาจต้องการติดตามผู้ที่ลงทะเบียนหลักสูตรปัจจุบันและหลักสูตรก่อนหน้า เพิ่มคุณสมบัติการนำทางสองอย่างสำหรับคลาสการลงทะเบียน

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 CurrCourse { get; set; }
   public virtual Course PrevCourse { get; set; }
   public virtual Student Student { get; set; }
}

ในทำนองเดียวกันคุณจะต้องเพิ่มในชั้นเรียนหลักสูตรที่อ้างอิงโดยคุณสมบัติเหล่านี้ คลาสหลักสูตรมีคุณสมบัติการนำทางกลับไปที่คลาสการลงทะเบียนซึ่งมีการลงทะเบียนปัจจุบันและก่อนหน้าทั้งหมด

public class Course {

   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]

   public int Credits { get; set; }
   public virtual ICollection<Enrollment> CurrEnrollments { get; set; }
   public virtual ICollection<Enrollment> PrevEnrollments { get; set; }
}

Code First สร้างคอลัมน์คีย์ต่างประเทศของ {Class Name} _ {Primary Key} ถ้าคุณสมบัติ Foreign Key ไม่รวมอยู่ในคลาสใดคลาสหนึ่งดังที่แสดงในคลาสด้านบน เมื่อสร้างฐานข้อมูลคุณจะเห็นคีย์ต่างประเทศต่อไปนี้

อย่างที่คุณเห็นว่า Code first ไม่สามารถจับคู่คุณสมบัติในสองคลาสได้ด้วยตัวเอง ตารางฐานข้อมูลสำหรับการลงทะเบียนควรมีคีย์ต่างประเทศหนึ่งคีย์สำหรับ CurrCourse และอีกหนึ่งคีย์สำหรับ PrevCourse แต่ Code First จะสร้างคุณสมบัติคีย์ต่างประเทศสี่รายการ ได้แก่

  • CurrCourse _CourseID
  • PrevCourse _CourseID
  • Course_CourseID และ
  • Course_CourseID1

ในการแก้ไขปัญหาเหล่านี้คุณสามารถใช้คำอธิบายประกอบ InverseProperty เพื่อระบุการจัดตำแหน่งของคุณสมบัติ

public class Course {

   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]

   public int Credits { get; set; }
   [InverseProperty("CurrCourse")]

   public virtual ICollection<Enrollment> CurrEnrollments { get; set; }
   [InverseProperty("PrevCourse")]

   public virtual ICollection<Enrollment> PrevEnrollments { get; set; }
}

ดังที่คุณเห็นแอตทริบิวต์ InverseProperty ถูกนำไปใช้ในคลาสหลักสูตรข้างต้นโดยระบุคุณสมบัติอ้างอิงของคลาสการลงทะเบียนที่เป็นของ ตอนนี้ Code First จะสร้างฐานข้อมูลและสร้างคอลัมน์คีย์ต่างประเทศเพียงสองคอลัมน์ในตารางการลงทะเบียนดังที่แสดงในภาพต่อไปนี้

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

Fluent API เป็นวิธีขั้นสูงในการระบุการกำหนดค่าโมเดลที่ครอบคลุมทุกสิ่งที่คำอธิบายประกอบข้อมูลสามารถทำได้นอกเหนือจากการกำหนดค่าขั้นสูงบางอย่างที่ไม่สามารถทำได้ด้วยคำอธิบายประกอบข้อมูล คำอธิบายประกอบข้อมูลและ API ที่คล่องแคล่วสามารถใช้ร่วมกันได้ แต่ Code First ให้ความสำคัญกับ Fluent API> คำอธิบายประกอบข้อมูล> ข้อตกลงเริ่มต้น

  • Fluent API เป็นอีกวิธีหนึ่งในการกำหนดค่าคลาสโดเมนของคุณ

  • Code First Fluent API สามารถเข้าถึงได้บ่อยที่สุดโดยการแทนที่เมธอด OnModelCreating บน DbContext ที่ได้รับของคุณ

  • Fluent API มีฟังก์ชันการทำงานสำหรับการกำหนดค่ามากกว่า DataAnnotations Fluent API รองรับการแมปประเภทต่อไปนี้

ในบทนี้เราจะดำเนินการต่อด้วยตัวอย่างง่ายๆซึ่งประกอบด้วยคลาสนักเรียนหลักสูตรและการลงทะเบียนและคลาสบริบทหนึ่งคลาสที่มีชื่อ MyContext ดังแสดงในโค้ดต่อไปนี้

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

}

ในการเข้าถึง Fluent 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; }
}

DbModelBuilder ใช้เพื่อแม็พคลาส CLR กับสกีมาฐานข้อมูล เป็นคลาสหลักและคุณสามารถกำหนดค่าคลาสโดเมนทั้งหมดของคุณได้ แนวทางรหัสเป็นศูนย์กลางในการสร้าง Entity Data Model (EDM) เรียกว่า Code First

Fluent API มีวิธีการที่สำคัญหลายวิธีในการกำหนดค่าเอนทิตีและคุณสมบัติเพื่อแทนที่อนุสัญญา Code First ต่างๆ ด้านล่างนี้คือบางส่วนของพวกเขา

เลขที่ ชื่อวิธีการและคำอธิบาย
1

ComplexType<TComplexType>

ลงทะเบียนประเภทเป็นประเภทที่ซับซ้อนในโมเดลและส่งคืนอ็อบเจ็กต์ที่สามารถใช้เพื่อกำหนดค่าประเภทที่ซับซ้อน วิธีนี้สามารถเรียกได้หลายครั้งสำหรับประเภทเดียวกันเพื่อดำเนินการกำหนดค่าหลายบรรทัด

2

Entity<TEntityType>

ลงทะเบียนประเภทเอนทิตีเป็นส่วนหนึ่งของโมเดลและส่งคืนอ็อบเจ็กต์ที่สามารถใช้เพื่อกำหนดค่าเอนทิตี วิธีนี้สามารถเรียกได้หลายครั้งเพื่อให้เอนทิตีเดียวกันดำเนินการกำหนดค่าหลายบรรทัด

3

HasKey<TKey>

กำหนดค่าคุณสมบัติคีย์หลักสำหรับประเภทเอนทิตีนี้

4

HasMany<TTargetEntity>

กำหนดค่าความสัมพันธ์จำนวนมากจากชนิดเอนทิตีนี้

5

HasOptional<TTargetEntity>

กำหนดค่าความสัมพันธ์ทางเลือกจากประเภทเอนทิตีนี้ อินสแตนซ์ของประเภทเอนทิตีจะสามารถบันทึกลงในฐานข้อมูลได้โดยไม่ต้องระบุความสัมพันธ์นี้ คีย์ภายนอกในฐานข้อมูลจะเป็นโมฆะ

6

HasRequired<TTargetEntity>

กำหนดค่าความสัมพันธ์ที่ต้องการจากประเภทเอนทิตีนี้ อินสแตนซ์ของประเภทเอนทิตีจะไม่สามารถบันทึกลงในฐานข้อมูลได้เว้นแต่จะระบุความสัมพันธ์นี้ คีย์ภายนอกในฐานข้อมูลจะไม่เป็นโมฆะ

7

Ignore<TProperty>

ไม่รวมคุณสมบัติจากโมเดลเพื่อไม่ให้แมปกับฐานข้อมูล (สืบทอดมาจาก StructuralTypeConfiguration <TStructuralType>)

8

Property<T>

กำหนดค่าคุณสมบัติโครงสร้างที่กำหนดไว้ในชนิดนี้ (สืบทอดมาจาก StructuralTypeConfiguration <TStructuralType>)

9

ToTable(String)

กำหนดค่าชื่อตารางที่แมปชนิดเอนทิตีนี้

Fluent API ช่วยให้คุณกำหนดค่าเอนทิตีหรือคุณสมบัติของพวกเขาได้ไม่ว่าคุณจะต้องการเปลี่ยนแปลงบางอย่างเกี่ยวกับวิธีที่พวกเขาแมปกับฐานข้อมูลหรือความสัมพันธ์ระหว่างกัน มีการแมปและการสร้างแบบจำลองมากมายที่คุณสามารถส่งผลกระทบได้โดยใช้การกำหนดค่า ต่อไปนี้เป็นประเภทหลักของการทำแผนที่ที่ Fluent API รองรับ -

  • การแมปเอนทิตี
  • การแมปคุณสมบัติ

การแมปเอนทิตี

การแมปเอนทิตีเป็นเพียงการแมปง่ายๆที่จะส่งผลต่อความเข้าใจของ Entity Framework เกี่ยวกับวิธีการแมปคลาสกับฐานข้อมูล ทั้งหมดนี้เราได้พูดถึงในคำอธิบายประกอบข้อมูลและที่นี่เราจะดูวิธีการบรรลุสิ่งเดียวกันโดยใช้ Fluent API

  • ดังนั้นแทนที่จะเข้าไปในคลาสโดเมนเพื่อเพิ่มการกำหนดค่าเหล่านี้เราสามารถทำได้ภายในบริบท

  • สิ่งแรกคือการแทนที่เมธอด OnModelCreating ซึ่งทำให้ modelBuilder ทำงานได้

สคีมาเริ่มต้น

สคีมาเริ่มต้นคือ dbo เมื่อสร้างฐานข้อมูล คุณสามารถใช้เมธอด HasDefaultSchema บน DbModelBuilder เพื่อระบุสกีมาฐานข้อมูลที่จะใช้สำหรับตารางทั้งหมดโพรซีเดอร์ที่เก็บไว้ ฯลฯ

ลองดูตัวอย่างต่อไปนี้ที่ใช้สคีมาของผู้ดูแลระบบ

public class MyContext : DbContext {
   public MyContext() : base("name = MyContextDB") {}

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      //Configure default schema
      modelBuilder.HasDefaultSchema("Admin");
   }
	
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

แมปเอนทิตีกับตาราง

ด้วยรูปแบบเริ่มต้น Code First จะสร้างตารางฐานข้อมูลด้วยชื่อของคุณสมบัติ DbSet ในคลาสบริบทเช่นหลักสูตรการลงทะเบียนและนักเรียน แต่ถ้าคุณต้องการชื่อตารางที่แตกต่างกันคุณสามารถแทนที่หลักการนี้และสามารถระบุชื่อตารางที่แตกต่างจากคุณสมบัติ DbSet ดังที่แสดงในโค้ดต่อไปนี้

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Map entity to table
   modelBuilder.Entity<Student>().ToTable("StudentData");
   modelBuilder.Entity<Course>().ToTable("CourseDetail");
   modelBuilder.Entity<Enrollment>().ToTable("EnrollmentInfo");
}

เมื่อสร้างฐานข้อมูลคุณจะเห็นชื่อตารางตามที่ระบุในเมธอด OnModelCreating

การแยกเอนทิตี (แมปเอนทิตีเป็นตารางหลายตาราง)

การแยกเอนทิตีช่วยให้คุณรวมข้อมูลที่มาจากตารางหลายตารางเป็นคลาสเดียวและสามารถใช้ได้เฉพาะกับตารางที่มีความสัมพันธ์แบบหนึ่งต่อกลุ่มเท่านั้น ลองดูตัวอย่างต่อไปนี้ที่ข้อมูลของนักเรียนถูกจับคู่เป็นสองตาราง

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Map entity to table
   modelBuilder.Entity<Student>().Map(sd ⇒ {
      sd.Properties(p ⇒ new { p.ID, p.FirstMidName, p.LastName });
      sd.ToTable("StudentData");
   })

   .Map(si ⇒ {
      si.Properties(p ⇒ new { p.ID, p.EnrollmentDate });
      si.ToTable("StudentEnrollmentInfo");
   });

   modelBuilder.Entity<Course>().ToTable("CourseDetail");
   modelBuilder.Entity<Enrollment>().ToTable("EnrollmentInfo");
}

ในโค้ดด้านบนคุณจะเห็นว่าเอนทิตี Student ถูกแบ่งออกเป็นสองตารางต่อไปนี้โดยการแมปคุณสมบัติบางอย่างกับตาราง StudentData และคุณสมบัติบางอย่างกับตาราง StudentEnrollmentInfo โดยใช้เมธอด Map

  • StudentData - ประกอบด้วย Student FirstMidName และนามสกุล

  • StudentEnrollmentInfo - ประกอบด้วย EnrollmentDate

เมื่อสร้างฐานข้อมูลคุณจะเห็นตารางต่อไปนี้ในฐานข้อมูลของคุณดังแสดงในภาพต่อไปนี้

การแมปคุณสมบัติ

วิธีคุณสมบัติใช้เพื่อกำหนดค่าแอตทริบิวต์สำหรับคุณสมบัติแต่ละรายการที่เป็นของเอนทิตีหรือประเภทที่ซับซ้อน เมธอดคุณสมบัติถูกใช้เพื่อรับอ็อบเจ็กต์คอนฟิกูเรชันสำหรับคุณสมบัติที่กำหนด คุณยังสามารถแมปและกำหนดค่าคุณสมบัติของคลาสโดเมนของคุณโดยใช้ Fluent API

การกำหนดค่าคีย์หลัก

หลักการเริ่มต้นสำหรับคีย์หลักคือ -

  • Class กำหนดคุณสมบัติที่มีชื่อเป็น“ ID” หรือ“ Id”
  • ชื่อคลาสตามด้วย“ ID” หรือ“ Id”

ถ้าชั้นเรียนของคุณไม่เป็นไปตามแบบแผนเริ่มต้นสำหรับคีย์หลักดังที่แสดงในรหัสต่อไปนี้ของคลาสนักเรียน -

public class Student {
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

จากนั้นในการตั้งค่าคุณสมบัติให้เป็นคีย์หลักอย่างชัดเจนคุณสามารถใช้เมธอด HasKey ดังที่แสดงในโค้ดต่อไปนี้ -

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
	
   // Configure Primary Key
   modelBuilder.Entity<Student>().HasKey<int>(s ⇒ s.StdntID); 
}

กำหนดค่าคอลัมน์

ใน Entity Framework โดยค่าเริ่มต้น Code First จะสร้างคอลัมน์สำหรับคุณสมบัติที่มีชื่อลำดับและประเภทข้อมูลเดียวกัน แต่คุณยังสามารถแทนที่หลักการนี้ได้ดังแสดงในรหัสต่อไปนี้

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Configure EnrollmentDate Column
   modelBuilder.Entity<Student>().Property(p ⇒ p.EnrollmentDate)
	
   .HasColumnName("EnDate")
   .HasColumnType("DateTime")
   .HasColumnOrder(2);
}

กำหนดค่า MaxLength Property

ในตัวอย่างต่อไปนี้คุณสมบัติชื่อหลักสูตรควรมีความยาวไม่เกิน 24 อักขระ เมื่อผู้ใช้ระบุค่ายาวกว่า 24 อักขระผู้ใช้จะได้รับข้อยกเว้น DbEntityValidationException

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
   modelBuilder.Entity<Course>().Property(p ⇒ p.Title).HasMaxLength(24);
}

กำหนดค่าคุณสมบัติ Null หรือ NotNull

ในตัวอย่างต่อไปนี้จำเป็นต้องมีคุณสมบัติชื่อหลักสูตรเพื่อใช้เมธอด IsRequired เพื่อสร้างคอลัมน์ NotNull ในทำนองเดียวกัน Student EnrollmentDate เป็นทางเลือกดังนั้นเราจะใช้วิธี IsOptional เพื่อให้ค่า null ในคอลัมน์นี้ดังแสดงในรหัสต่อไปนี้

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
   modelBuilder.Entity<Course>().Property(p ⇒ p.Title).IsRequired();
   modelBuilder.Entity<Student>().Property(p ⇒ p.EnrollmentDate).IsOptional();
	
   //modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
   //.HasColumnName("FirstName"); 
}

การกำหนดค่าความสัมพันธ์

ความสัมพันธ์ในบริบทของฐานข้อมูลคือสถานการณ์ที่มีอยู่ระหว่างตารางฐานข้อมูลเชิงสัมพันธ์สองตารางเมื่อตารางหนึ่งมีคีย์ต่างประเทศที่อ้างอิงคีย์หลักของตารางอื่น เมื่อทำงานกับ Code First คุณกำหนดโมเดลของคุณโดยกำหนดคลาส CLR ของโดเมนของคุณ ตามค่าเริ่มต้น Entity Framework จะใช้ข้อตกลง Code First เพื่อแม็พคลาสของคุณกับสกีมาฐานข้อมูล

  • หากคุณใช้หลักการตั้งชื่อ Code First ในกรณีส่วนใหญ่คุณสามารถใช้ Code First เพื่อตั้งค่าความสัมพันธ์ระหว่างตารางของคุณตามคีย์ต่างประเทศและคุณสมบัติการนำทาง

  • หากไม่ตรงตามอนุสัญญาเหล่านั้นนอกจากนี้ยังมีการกำหนดค่าที่คุณสามารถใช้เพื่อส่งผลกระทบต่อความสัมพันธ์ระหว่างคลาสและวิธีที่ความสัมพันธ์เหล่านั้นรับรู้ในฐานข้อมูลเมื่อคุณเพิ่มการกำหนดค่าใน Code First

  • บางส่วนมีอยู่ในคำอธิบายประกอบข้อมูลและคุณสามารถใช้คำอธิบายประกอบที่ซับซ้อนยิ่งขึ้นได้ด้วย Fluent API

กำหนดค่าความสัมพันธ์แบบหนึ่งต่อหนึ่ง

เมื่อคุณกำหนดความสัมพันธ์แบบหนึ่งต่อกลุ่มในโมเดลของคุณคุณจะใช้คุณสมบัติการนำทางอ้างอิงในแต่ละคลาส ในฐานข้อมูลทั้งสองตารางสามารถมีระเบียนเดียวที่ด้านใดด้านหนึ่งของความสัมพันธ์ ค่าคีย์หลักแต่ละค่าเกี่ยวข้องกับเรกคอร์ดเดียว (หรือไม่มีเรกคอร์ด) ในตารางที่เกี่ยวข้อง

  • ความสัมพันธ์แบบหนึ่งต่อหนึ่งจะถูกสร้างขึ้นหากทั้งสองคอลัมน์ที่เกี่ยวข้องเป็นคีย์หลักหรือมีข้อ จำกัด เฉพาะ

  • ในความสัมพันธ์แบบหนึ่งต่อกลุ่มคีย์หลักจะทำหน้าที่เป็นคีย์ต่างประเทศเพิ่มเติมและไม่มีคอลัมน์คีย์ต่างประเทศแยกสำหรับตารางใดตารางหนึ่ง

  • ความสัมพันธ์ประเภทนี้ไม่ธรรมดาเนื่องจากข้อมูลส่วนใหญ่ที่เกี่ยวข้องในลักษณะนี้ทั้งหมดจะอยู่ในตารางเดียว

ลองดูตัวอย่างต่อไปนี้ที่เราจะเพิ่มคลาสอื่นในโมเดลของเราเพื่อสร้างความสัมพันธ์แบบหนึ่งต่อกลุ่ม

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 StudentLogIn StudentLogIn { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class StudentLogIn {
   [Key, ForeignKey("Student")]
   public int ID { get; set; }
   public string EmailID { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

ดังที่คุณเห็นในโค้ดด้านบนว่าแอตทริบิวต์ Key และ ForeignKey ใช้สำหรับคุณสมบัติ ID ในคลาส StudentLogIn เพื่อทำเครื่องหมายเป็นคีย์หลักและ Foreign Key

ในการกำหนดค่าความสัมพันธ์แบบหนึ่งต่อศูนย์หรือหนึ่งระหว่าง Student และ StudentLogIn โดยใช้ Fluent API คุณต้องแทนที่เมธอด OnModelCreating ดังที่แสดงในรหัสต่อไปนี้

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure ID as PK for StudentLogIn
   modelBuilder.Entity<StudentLogIn>()
   .HasKey(s ⇒ s.ID);

   // Configure ID as FK for StudentLogIn
   modelBuilder.Entity<Student>()
   
   .HasOptional(s ⇒ s.StudentLogIn) //StudentLogIn is optional
   .WithRequired(t ⇒ t.Student); // Create inverse relationship
}

ในกรณีส่วนใหญ่ Entity Framework สามารถอนุมานได้ว่าประเภทใดขึ้นอยู่กับและชนิดใดเป็นตัวหลักในความสัมพันธ์ อย่างไรก็ตามเมื่อจำเป็นต้องใช้จุดจบทั้งสองข้างหรือทั้งสองด้านเป็นทางเลือก Entity Framework ไม่สามารถระบุการพึ่งพาและหลักได้ เมื่อต้องการความสัมพันธ์ทั้งสองด้านคุณสามารถใช้ HasRequired ดังแสดงในโค้ดต่อไปนี้

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure ID as PK for StudentLogIn
   modelBuilder.Entity<StudentLogIn>()
   .HasKey(s ⇒ s.ID);

   // Configure ID as FK for StudentLogIn
   modelBuilder.Entity<Student>()
   .HasRequired(r ⇒ r.Student)
   .WithOptional(s ⇒ s.StudentLogIn);  
}

เมื่อสร้างฐานข้อมูลคุณจะเห็นความสัมพันธ์นั้นถูกสร้างขึ้นดังที่แสดงในภาพต่อไปนี้

กำหนดค่าความสัมพันธ์แบบหนึ่งต่อกลุ่ม

ตารางคีย์หลักประกอบด้วยเรกคอร์ดเดียวที่เกี่ยวข้องกับไม่มีหนึ่งเรกคอร์ดในตารางที่เกี่ยวข้อง นี่คือประเภทของความสัมพันธ์ที่ใช้บ่อยที่สุด

  • ในความสัมพันธ์ประเภทนี้แถวในตาราง A สามารถมีแถวที่ตรงกันได้หลายแถวในตาราง B แต่แถวในตาราง B สามารถมีแถวที่ตรงกันเพียงแถวเดียวในตาราง A

  • คีย์ต่างประเทศถูกกำหนดไว้บนตารางซึ่งแสดงถึงจุดสิ้นสุดของความสัมพันธ์

  • ตัวอย่างเช่นในแผนภาพด้านบนตารางนักเรียนและการลงทะเบียนมีความสัมพันธ์แบบเดียวกันนักเรียนแต่ละคนอาจมีการลงทะเบียนหลายครั้ง แต่การลงทะเบียนแต่ละครั้งเป็นของนักเรียนเพียงคนเดียว

ด้านล่างนี้คือ Student and Enrollment ซึ่งมีความสัมพันธ์แบบหนึ่งต่อกลุ่ม แต่คีย์ต่างประเทศในตารางการลงทะเบียนไม่เป็นไปตามข้อตกลงเริ่มต้นของ Code First

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
	
   //StdntID is not following code first conventions name
   public int StdntID { 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 StudentLogIn StudentLogIn { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ในกรณีนี้ในการกำหนดค่าความสัมพันธ์แบบหนึ่งต่อกลุ่มโดยใช้ Fluent API คุณต้องใช้เมธอด HasForeignKey ดังที่แสดงในโค้ดต่อไปนี้

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Configure FK for one-to-many relationship
   modelBuilder.Entity<Enrollment>()

   .HasRequired<Student>(s ⇒ s.Student)
   .WithMany(t ⇒ t.Enrollments)
   .HasForeignKey(u ⇒ u.StdntID);  
}

เมื่อสร้างฐานข้อมูลคุณจะเห็นว่าความสัมพันธ์ถูกสร้างขึ้นดังที่แสดงในภาพต่อไปนี้

ในตัวอย่างข้างต้นเมธอด HasRequired ระบุว่าคุณสมบัติการนำทางของนักเรียนต้องเป็น Null ดังนั้นคุณต้องกำหนด Student ที่มีเอนทิตีการลงทะเบียนทุกครั้งที่คุณเพิ่มหรืออัปเดตการลงทะเบียน ในการจัดการสิ่งนี้เราจำเป็นต้องใช้เมธอด HasOptional แทนวิธี HasRequired

กำหนดค่าความสัมพันธ์แบบกลุ่มต่อกลุ่ม

แต่ละเร็กคอร์ดในทั้งสองตารางสามารถเกี่ยวข้องกับจำนวนเรกคอร์ด (หรือไม่มีเรกคอร์ด) ในตารางอื่น

  • คุณสามารถสร้างความสัมพันธ์ดังกล่าวได้โดยการกำหนดตารางที่สามเรียกว่าตารางทางแยกซึ่งคีย์หลักประกอบด้วยคีย์ต่างประเทศจากทั้งตาราง A และตาราง B

  • ตัวอย่างเช่นตารางนักเรียนและตารางหลักสูตรมีความสัมพันธ์แบบกลุ่มต่อกลุ่ม

ต่อไปนี้เป็นชั้นเรียนของนักเรียนและหลักสูตรที่นักเรียนและหลักสูตรมีความสัมพันธ์กันหลายรูปแบบเนื่องจากทั้งสองชั้นเรียนมีคุณสมบัติการนำทางนักเรียนและหลักสูตรที่เป็นคอลเล็กชัน กล่าวอีกนัยหนึ่งเอนทิตีหนึ่งมีคอลเลกชันเอนทิตีอื่น

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<Course> Courses { 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<Student> Students { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ในการกำหนดค่าความสัมพันธ์แบบกลุ่มต่อกลุ่มระหว่างนักเรียนและหลักสูตรคุณสามารถใช้ Fluent API ดังที่แสดงในรหัสต่อไปนี้

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure many-to-many relationship
   modelBuilder.Entity<Student>()
   .HasMany(s ⇒ s.Courses) 
   .WithMany(s ⇒ s.Students);
}

หลักการเริ่มต้นของ Code First ถูกใช้เพื่อสร้างตารางการรวมเมื่อสร้างฐานข้อมูล ด้วยเหตุนี้ตาราง StudentCourses จึงถูกสร้างขึ้นด้วยคอลัมน์ Course_CourseID และ Student_ID ดังที่แสดงในภาพต่อไปนี้

หากคุณต้องการระบุชื่อตารางการรวมและชื่อของคอลัมน์ในตารางคุณต้องทำการกำหนดค่าเพิ่มเติมโดยใช้เมธอดแผนที่

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure many-to-many relationship 
   modelBuilder.Entity<Student>()

   .HasMany(s ⇒ s.Courses)
   .WithMany(s ⇒ s.Students)
   
   .Map(m ⇒ {
      m.ToTable("StudentCoursesTable");
      m.MapLeftKey("StudentID");
      m.MapRightKey("CourseID");
   }); 
}

คุณสามารถดูได้ว่าเมื่อใดที่สร้างฐานข้อมูลชื่อตารางและคอลัมน์จะถูกสร้างขึ้นตามที่ระบุไว้ในโค้ดด้านบน

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ใน Entity Framework Seed ถูกนำมาใช้ใน EF 4.1 และทำงานร่วมกับตัวเริ่มต้นฐานข้อมูล แนวคิดทั่วไปของไฟล์Seed Methodคือการเริ่มต้นข้อมูลลงในฐานข้อมูลที่ Code First สร้างขึ้นหรือพัฒนาโดย Migrations ข้อมูลนี้มักเป็นข้อมูลการทดสอบ แต่อาจเป็นข้อมูลอ้างอิงเช่นรายชื่อนักเรียนที่รู้จักหลักสูตร ฯลฯ เมื่อข้อมูลเริ่มต้นข้อมูลจะดำเนินการดังต่อไปนี้ -

  • ตรวจสอบว่ามีฐานข้อมูลเป้าหมายอยู่แล้วหรือไม่
  • หากเป็นเช่นนั้นโมเดล Code First ปัจจุบันจะถูกเปรียบเทียบกับโมเดลที่เก็บไว้ในข้อมูลเมตาในฐานข้อมูล
  • ฐานข้อมูลจะหายไปหากโมเดลปัจจุบันไม่ตรงกับโมเดลในฐานข้อมูล
  • ฐานข้อมูลจะถูกสร้างขึ้นหากถูกทิ้งหรือไม่มีอยู่ตั้งแต่แรก
  • หากฐานข้อมูลถูกสร้างขึ้นเมธอด initializer Seed จะถูกเรียก

เมธอด Seed ใช้อ็อบเจ็กต์บริบทฐานข้อมูลเป็นพารามิเตอร์อินพุตและโค้ดในเมธอดใช้อ็อบเจ็กต์นั้นเพื่อเพิ่มเอนทิตีใหม่ให้กับฐานข้อมูล ในการเพาะข้อมูลลงในฐานข้อมูลของคุณคุณต้องแทนที่เมธอด Seed มาดูตัวอย่างต่อไปนี้ซึ่งข้อมูลดีฟอลต์บางส่วนเริ่มต้นในฐานข้อมูลในคลาสภายใน

private class UniDBInitializer<T> : DropCreateDatabaseAlways<MyContext> {

   protected override void Seed(MyContext context) {

      IList<Student> students = new List<Student>();

      students.Add(new Student() {
         FirstMidName = "Andrew", 
         LastName = "Peters", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      });

      students.Add(new Student() {
         FirstMidName = "Brice", 
         LastName = "Lambson", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      });

      students.Add(new Student() {
         FirstMidName = "Rowan", 
         LastName = "Miller", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      });

      foreach (Student student in students)
      context.Students.Add(student);
      base.Seed(context);
   }
}

ในรหัสด้านบนตารางนักเรียนจะเริ่มต้น คุณต้องตั้งค่าคลาส DB initializer นี้ในคลาสบริบทดังที่แสดงในโค้ดต่อไปนี้

public MyContext() : base("name=MyContextDB") {
   Database.SetInitializer<MyContext>(new UniDBInitializer<MyContext>());
}

ต่อไปนี้คือการใช้คลาส MyContext แบบสมบูรณ์ซึ่งมีคลาส DB initializer ด้วย

public class MyContext : DbContext {

   public MyContext() : base("name=MyContextDB") {
      Database.SetInitializer<MyContext>(new UniDBInitializer<MyContext>());
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
	
   private class UniDBInitializer<T> : DropCreateDatabaseAlways<MyContext> {

      protected override void Seed(MyContext context) {

         IList<Student> students = new List<Student>();
			
         students.Add(new Student() {
            FirstMidName = "Andrew", 
            LastName = "Peters", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString()) 
         });

         students.Add(new Student() {
            FirstMidName = "Brice", 
            LastName = "Lambson", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         students.Add(new Student() {
            FirstMidName = "Rowan", 
            LastName = "Miller", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         foreach (Student student in students)
         context.Students.Add(student);
         base.Seed(context);
      }
   } 
}

เมื่อตัวอย่างข้างต้นถูกรวบรวมและดำเนินการคุณจะเห็นข้อมูลในฐานข้อมูลดังที่แสดงในภาพต่อไปนี้

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

Entity Framework 4.3 มีคุณลักษณะ Code First Migrations ใหม่ที่ช่วยให้คุณสามารถพัฒนาสคีมาฐานข้อมูลได้เพิ่มขึ้นเมื่อโมเดลของคุณเปลี่ยนแปลงไปตามกาลเวลา สำหรับนักพัฒนาส่วนใหญ่นี่เป็นการปรับปรุงครั้งใหญ่ของตัวเลือกตัวเริ่มต้นฐานข้อมูลจากรุ่น 4.1 และ 4.2 ที่ทำให้คุณต้องอัปเดตฐานข้อมูลด้วยตนเองหรือวางและสร้างใหม่เมื่อโมเดลของคุณเปลี่ยนไป

  • ก่อน Entity Framework 4.3 หากคุณมีข้อมูล (นอกเหนือจากข้อมูล seed) หรือ Stored Procedures ทริกเกอร์ ฯลฯ ที่มีอยู่ในฐานข้อมูลของคุณกลยุทธ์เหล่านี้ใช้เพื่อทิ้งฐานข้อมูลทั้งหมดและสร้างใหม่ดังนั้นคุณจะสูญเสียข้อมูลและฐานข้อมูลอื่น ๆ วัตถุ

  • ด้วยการย้ายข้อมูลจะอัปเดตสคีมาฐานข้อมูลโดยอัตโนมัติเมื่อโมเดลของคุณเปลี่ยนแปลงโดยไม่สูญเสียข้อมูลที่มีอยู่หรือวัตถุฐานข้อมูลอื่น ๆ

  • ใช้ตัวเริ่มต้นฐานข้อมูลใหม่ที่เรียกว่า MigrateDatabaseToLatestVersion

การย้ายข้อมูลมีสองประเภท -

  • การย้ายข้อมูลอัตโนมัติ
  • การโยกย้ายตามรหัส

การย้ายข้อมูลอัตโนมัติ

Automated Migration ถูกนำมาใช้ครั้งแรกใน Entity framework 4.3 ในการย้ายข้อมูลอัตโนมัติคุณไม่จำเป็นต้องดำเนินการย้ายฐานข้อมูลด้วยตนเองในไฟล์โค้ด ตัวอย่างเช่นสำหรับการเปลี่ยนแปลงแต่ละครั้งคุณจะต้องเปลี่ยนคลาสโดเมนของคุณด้วย แต่ด้วยการโยกย้ายอัตโนมัติคุณเพียงแค่เรียกใช้คำสั่งใน Package Manager Console เพื่อดำเนินการนี้

มาดูขั้นตอนการย้ายข้อมูลอัตโนมัติแบบทีละขั้นตอนต่อไปนี้

เมื่อคุณใช้แนวทาง Code First คุณจะไม่มีฐานข้อมูลสำหรับแอปพลิเคชันของคุณ

ในตัวอย่างนี้เราจะเริ่มต้นด้วยคลาสพื้นฐาน 3 คลาสเช่นนักเรียนหลักสูตรและการลงทะเบียนตามที่แสดงในโค้ดต่อไปนี้

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; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

ต่อไปนี้เป็นคลาสบริบท

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

ก่อนเรียกใช้แอปพลิเคชันคุณต้องเปิดใช้งานการย้ายข้อมูลอัตโนมัติ

Step 1 - เปิดคอนโซล Package Manger จาก Tools → NuGet Package Manger → Package Manger Console

Step 2 - ในการเปิดใช้งานการโอนย้ายอัตโนมัติให้รันคำสั่งต่อไปนี้ใน Package Manager Console

PM> enable-migrations -EnableAutomaticMigrations:$true

Step 3 - เมื่อคำสั่งทำงานสำเร็จคำสั่งจะสร้างคลาส Configuration ที่ปิดผนึกไว้ภายในในโฟลเดอร์ Migration ของโปรเจ็กต์ของคุณดังที่แสดงในโค้ดต่อไปนี้

namespace EFCodeFirstDemo.Migrations {

   using System;
   using System.Data.Entity;
   using System.Data.Entity.Migrations;
   using System.Linq;
	
   internal sealed class Configuration : DbMigrationsConfiguration<EFCodeFirstDemo.MyContext> {

      public Configuration() {
         AutomaticMigrationsEnabled = true;
         ContextKey = "EFCodeFirstDemo.MyContext";
      }

      protected override void Seed(EFCodeFirstDemo.MyContext 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. E.g.

         //  context.People.AddOrUpdate(
            //  p ⇒ p.FullName, 
            //  new Person { FullName = "Andrew Peters" }, 
            //  new Person { FullName = "Brice Lambson" }, 
            //  new Person { FullName = "Rowan Miller" }
         //  );
      }
   }
}

Step 4 - ตั้งค่าตัวเริ่มต้นฐานข้อมูลในคลาสบริบทด้วยกลยุทธ์การเริ่มต้น DB ใหม่ MigrateDatabaseToLatestVersion

public class MyContext : DbContext {

   public MyContext() : base("MyContextDB") {
      Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, 
         EFCodeFirstDemo.Migrations.Configuration>("MyContextDB"));
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }

}

Step 5- คุณได้ตั้งค่าการย้ายข้อมูลอัตโนมัติ เมื่อคุณเรียกใช้แอปพลิเคชันของคุณแอปพลิเคชันจะดูแลการโยกย้ายโดยอัตโนมัติเมื่อคุณเปลี่ยนรุ่น

Step 6- ดังที่คุณเห็นว่าตารางระบบ __MigrationHistory หนึ่งตารางถูกสร้างขึ้นในฐานข้อมูลของคุณพร้อมกับตารางอื่นด้วย ใน __MigrationHistory การโอนย้ายอัตโนมัติจะเก็บรักษาประวัติการเปลี่ยนแปลงฐานข้อมูล

Step 7- เมื่อคุณเพิ่มคลาสเอนทิตีอื่นเป็นคลาสโดเมนของคุณและดำเนินการแอปพลิเคชันของคุณมันจะสร้างตารางในฐานข้อมูลของคุณ มาเพิ่มคลาส StudentLogIn ต่อไปนี้

public class StudentLogIn {
   [Key, ForeignKey("Student")]
   public int ID { get; set; }
   public string EmailID { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

Step 8 - อย่าลืมเพิ่ม DBSet สำหรับคลาสที่กล่าวถึงข้างต้นในคลาสบริบทของคุณดังที่แสดงในโค้ดต่อไปนี้

public virtual DbSet<StudentLogIn> StudentsLogIn { get; set; }

Step 9 - เรียกใช้แอปพลิเคชันของคุณอีกครั้งและคุณจะเห็นว่ามีการเพิ่มตาราง StudentsLogIn ในฐานข้อมูลของคุณ

ขั้นตอนข้างต้นที่กล่าวถึงสำหรับการย้ายข้อมูลอัตโนมัติจะใช้ได้กับเอนทิตีของคุณเท่านั้น ตัวอย่างเช่นหากต้องการเพิ่มคลาสเอนทิตีอื่นหรือลบคลาสเอนทิตีที่มีอยู่ออกก็จะโอนย้ายได้สำเร็จ แต่ถ้าคุณเพิ่มหรือลบคุณสมบัติใด ๆ ในคลาสเอนทิตีของคุณมันจะทำให้เกิดข้อยกเว้น

Step 10 - ในการจัดการการย้ายคุณสมบัติคุณต้องตั้งค่า AutomaticMigrationDataLossAllowed = true ในคอนสตรัคเตอร์คลาสคอนฟิกูเรชัน

public Configuration() {
   AutomaticMigrationsEnabled = true;
   AutomaticMigrationDataLossAllowed = true;
   ContextKey = "EFCodeFirstDemo.MyContext";
}

การโยกย้ายตามรหัส

เมื่อคุณพัฒนาแอปพลิเคชันใหม่โมเดลข้อมูลของคุณจะเปลี่ยนแปลงบ่อยและทุกครั้งที่โมเดลมีการเปลี่ยนแปลงโมเดลจะไม่ซิงค์กับฐานข้อมูล คุณได้กำหนดค่า Entity Framework ให้วางและสร้างฐานข้อมูลใหม่โดยอัตโนมัติทุกครั้งที่คุณเปลี่ยนโมเดลข้อมูล การโยกย้ายโดยใช้รหัสมีประโยชน์เมื่อคุณต้องการควบคุมการย้ายข้อมูลมากขึ้น

  • เมื่อคุณเพิ่มลบหรือเปลี่ยนคลาสเอนทิตีหรือเปลี่ยนคลาส DbContext ของคุณในครั้งถัดไปที่คุณเรียกใช้แอปพลิเคชันแอปพลิเคชันจะลบฐานข้อมูลที่มีอยู่ของคุณโดยอัตโนมัติสร้างใหม่ที่ตรงกับโมเดลและขยายด้วยข้อมูลทดสอบ

  • คุณลักษณะ Code First Migrations สามารถแก้ปัญหานี้ได้โดยการเปิดใช้งาน Code First เพื่ออัปเดตสกีมาฐานข้อมูลแทนที่จะทิ้งและสร้างฐานข้อมูลใหม่ ในการปรับใช้แอปพลิเคชันคุณจะต้องเปิดใช้งานการย้ายข้อมูล

นี่คือกฎพื้นฐานในการย้ายการเปลี่ยนแปลงในฐานข้อมูล -

  • เปิดใช้งานการย้ายข้อมูล
  • เพิ่มการย้ายข้อมูล
  • อัปเดตฐานข้อมูล

มาดูขั้นตอนการโอนย้ายรหัสฐานทีละขั้นตอนต่อไปนี้

เมื่อคุณใช้รหัสแนวทางแรกคุณจะไม่มีฐานข้อมูลสำหรับแอปพลิเคชันของคุณ

ในตัวอย่างนี้เราจะเริ่มต้นอีกครั้งด้วยคลาสพื้นฐาน 3 คลาสเช่นนักเรียนหลักสูตรและการลงทะเบียนตามที่แสดงในโค้ดต่อไปนี้

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; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

ต่อไปนี้เป็นคลาสบริบท

public class MyContext : DbContext {

   public MyContext() : base("MyContextDB") {
      Database.SetInitializer(new MigrateDatabaseToLatestVersion<
         MyContext, EFCodeFirstDemo.Migrations.Configuration>("MyContextDB"));
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }

}

Step 1 - ก่อนเรียกใช้แอปพลิเคชันคุณต้องเปิดใช้งานการย้ายข้อมูล

Step 2 - เปิดคอนโซล Package Manager จาก Tools → NuGet Package Manger → Package Manger Console

Step 3 - เปิดใช้งานการย้ายข้อมูลแล้วตอนนี้เพิ่มการย้ายข้อมูลในแอปพลิเคชันของคุณโดยดำเนินการคำสั่งต่อไปนี้

PM> add-migration "UniDB Schema"

Step 4 - เมื่อดำเนินการคำสั่งสำเร็จคุณจะเห็นไฟล์ใหม่ถูกสร้างขึ้นในโฟลเดอร์ Migration พร้อมชื่อของพารามิเตอร์ที่คุณส่งไปยังคำสั่งพร้อมคำนำหน้าเวลาประทับดังที่แสดงในภาพต่อไปนี้

Step 5 - คุณสามารถสร้างหรืออัปเดตฐานข้อมูลโดยใช้คำสั่ง“ update-database”

PM> Update-Database -Verbose

แฟล็ก "-Verbose" ระบุเพื่อแสดงคำสั่ง SQL ที่ใช้กับฐานข้อมูลเป้าหมายในคอนโซล

Step 6 - เพิ่มคุณสมบัติ 'อายุ' อีกหนึ่งรายการในชั้นเรียนของนักเรียนจากนั้นดำเนินการคำสั่งอัปเดต

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public int Age { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

เมื่อคุณรัน PM → Update-Database - Verbose เมื่อคำสั่งถูกเรียกใช้งานสำเร็จคุณจะเห็นว่าคอลัมน์ใหม่ Age ถูกเพิ่มในฐานข้อมูลของคุณ

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ในบทนี้เราจะเรียนรู้วิธีการย้ายการเปลี่ยนแปลงไปยังฐานข้อมูลเมื่อมี DbContext หลายคลาสในแอปพลิเคชัน

  • DbContext หลายตัวถูกนำมาใช้ครั้งแรกใน Entity Framework 6.0
  • หลายบริบทคลาสอาจเป็นของฐานข้อมูลเดียวหรือสองฐานข้อมูลที่แตกต่างกัน

ในตัวอย่างของเราเราจะกำหนดคลาสบริบทสองคลาสสำหรับฐานข้อมูลเดียวกัน ในโค้ดต่อไปนี้มีคลาส DbContext สองคลาสสำหรับนักเรียนและครู

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
}

public class MyStudentContext : DbContext {
   public MyStudentContext() : base("UniContextDB") {}
   public virtual DbSet<Student> Students { get; set; }
}

public class Teacher {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime HireDate { get; set; }
}

public class MyTeacherContext : DbContext {
   public MyTeacherContext() : base("UniContextDB") {}
   public virtual DbSet<Teacher> Teachers { get; set; }
}

ดังที่คุณเห็นในโค้ดด้านบนมีสองโมเดลที่เรียกว่า "นักเรียน" และ "ครู" แต่ละคนเชื่อมโยงกับคลาสบริบทที่เกี่ยวข้องโดยเฉพาะกล่าวคือ Student เชื่อมโยงกับ MyStudentContext และ Teacher เชื่อมโยงกับ MyTeacherContext

นี่คือกฎพื้นฐานในการโอนย้ายการเปลี่ยนแปลงในฐานข้อมูลเมื่อมีคลาสบริบทหลายคลาสภายในโปรเจ็กต์เดียวกัน

  • enable-migrations -ContextTypeName <DbContext-Name-with-Namespaces> MigrationsDirectory: <Migrations-Directory-Name>

  • Add-Migration -configuration <DbContext-Migrations-Configuration-Class-withNamespaces> <Migrations-Name>

  • อัพเดตฐานข้อมูล - คอนฟิกูเรชัน <DbContext-Migrations-Configuration-Class-withNamespaces> -Verbose

มาเปิดใช้งานการโอนย้ายสำหรับ MyStudentContext โดยดำเนินการคำสั่งต่อไปนี้ใน Package Manager Console

PM→ enable-migrations -ContextTypeName:EFCodeFirstDemo.MyStudentContext

เมื่อดำเนินการแล้วเราจะเพิ่มโมเดลในประวัติการย้ายข้อมูลและสำหรับสิ่งนั้นเราต้องเริ่มคำสั่ง add-migration ในคอนโซลเดียวกัน

PM→ add-migration -configuration EFCodeFirstDemo.Migrations.Configuration Initial

ตอนนี้ให้เราเพิ่มข้อมูลลงในตารางนักเรียนและครูในฐานข้อมูล

static void Main(string[] args) {

   using (var context = new MyStudentContext()) {
	
      //// 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())
         //Age = 24
      };

      context.Students.Add(student);

      var student1 = new Student {
         FirstMidName = "Mark",
         LastName = "Upston", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 30
      };

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

   using (var context = new MyTeacherContext()) {

      //// Create and save a new Teachers
      Console.WriteLine("Adding new teachers");

      var student = new Teacher {
         FirstMidName = "Alain", 
         LastName = "Bomer", 
         HireDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 24
      };

      context.Teachers.Add(student);

      var student1 = new Teacher {
         FirstMidName = "Mark", 
         LastName = "Upston", 
         HireDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 30
      };

      context.Teachers.Add(student1);
      context.SaveChanges();
  
      // Display all Teachers from the database
      var teachers = (from t in context.Teachers orderby t.FirstMidName
         select t).ToList<Teacher>();
		
      Console.WriteLine("Retrieve all teachers from the database:");

      foreach (var teacher in teachers) {
         string name = teacher.FirstMidName + " " + teacher.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", teacher.ID, name);
      }

      Console.WriteLine("Press any key to exit...");
      Console.ReadKey();
   }
}

เมื่อดำเนินการโค้ดด้านบนคุณจะเห็นว่ามีการสร้างตารางที่แตกต่างกันสองตารางสำหรับโมเดลที่แตกต่างกันสองแบบดังที่แสดงในภาพต่อไปนี้

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น

ก่อนหน้า Entity Framework 6 Entity Framework ไม่รู้จักเอนทิตีหรือประเภทที่ซับซ้อนที่ซ้อนอยู่ภายในเอนทิตีอื่นหรือประเภทที่ซับซ้อน เมื่อ Entity Framework สร้างแบบจำลองชนิดที่ซ้อนกันจะหายไป

ลองมาดูตัวอย่างง่ายๆที่เรามีโมเดลพื้นฐานที่มีสามเอนทิตีนักศึกษาหลักสูตรและการลงทะเบียน

  • มาเพิ่มคุณสมบัติ Identity ซึ่งเป็นประเภทบุคคล บุคคลคือเอนทิตีอื่นมีคุณสมบัติ BirthDate และ FatherName

  • ในเงื่อนไขของ Entity Framework เนื่องจากไม่มีข้อมูลประจำตัวและเป็นส่วนหนึ่งของเอนทิตีเป็นประเภทที่ซับซ้อนของ Entity Framework และเราได้รับการสนับสนุนสำหรับประเภทที่ซับซ้อนตั้งแต่เวอร์ชันแรกของ Entity Framework

  • ประเภทบุคคลไม่ซ้อนกันดังที่แสดงในรหัสต่อไปนี้

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
   public Person Identity { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class Person {

   public Person(string fatherName, DateTime birthDate) {
      FatherName = fatherName;
      BirthDate = birthDate;
   }
	
   public string FatherName { get; set; }
   public DateTime BirthDate { get; set; }
}

Entity Framework จะรู้วิธีคงประเภทบุคคลเมื่อใช้ในเวอร์ชันก่อนหน้าเช่นกัน

ด้วยการใช้ Entity Framework Power Tool เราจะดูว่า Entity Framework ตีความโมเดลอย่างไร คลิกขวาที่ไฟล์ Program.cs และเลือก Entity Framework → View Entity Data Model (อ่านอย่างเดียว)

ตอนนี้คุณจะเห็นว่าคุณสมบัติ Identity ถูกกำหนดไว้ในคลาสนักเรียน

หากเอนทิตีอื่นไม่ใช้คลาส Person นี้เราสามารถซ้อนไว้ในคลาส Student ได้ แต่ Entity Framework เวอร์ชันก่อนหน้านี้ไม่ยอมรับประเภทที่ซ้อนกัน

ในเวอร์ชันที่เก่ากว่าคุณจะสร้างแบบจำลองอีกครั้งไม่เพียง แต่จะไม่รู้จักประเภท แต่เนื่องจากไม่มีอยู่จึงไม่มีคุณสมบัติดังกล่าวดังนั้น Entity Framework จะไม่คงอยู่ประเภทบุคคลเลย

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
	
   public DateTime EnrollmentDate { get; set; }
   public Person Identity { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

   public class Person {

      public Person(string fatherName, DateTime birthDate) {
         FatherName = fatherName;
         BirthDate = birthDate;
      }

      public string FatherName { get; set; }
      public DateTime BirthDate { get; set; }
   }
}

ด้วย Entity Framework 6 เอนทิตีที่ซ้อนกันและประเภทที่ซับซ้อนจะได้รับการยอมรับ ในรหัสด้านบนคุณจะเห็นว่าบุคคลนั้นซ้อนอยู่ในชั้นเรียนของนักเรียน

เมื่อคุณใช้ Entity Framework Power Tool เพื่อแสดงว่า Entity Framework ตีความโมเดลในครั้งนี้อย่างไรมีคุณสมบัติ Identity จริงและประเภทที่ซับซ้อนของบุคคล ดังนั้น Entity Framework จะยังคงมีข้อมูลนั้นอยู่

ตอนนี้คุณจะเห็นว่า Identity เป็นประเภทเอนทิตีที่ซ้อนกันซึ่งไม่ได้รับการสนับสนุนก่อน Entity Framework 6

เราขอแนะนำให้คุณดำเนินการตามตัวอย่างข้างต้นในลักษณะทีละขั้นตอนเพื่อความเข้าใจที่ดีขึ้น