Entity Framework多對多關聯對映的實現
Entity Framework是微軟官方提供的一個ORM解決方案,它有純正的血統,比NHibernate更容易使用並且與現有其它官方框架配合更加密切。
時代不斷的在發展變化,記得10年前還是ADO(配合ASP)的天下,後來微軟推出了ADO.NET,再後來推出了ADO.NET Entity Framework,可見微軟在.NET與資料庫互動領域的作為。
下面我將以Entity Framework(簡稱EF)來演示一下在C#當中如何使用好這個非常“爽”的ORM工具。我們以大家比較熟悉的模型—學生和課程的多對多的關係(學生可以選擇多門課程、課程有可能有多個學生選擇)來進行演示。
第一步,建立一個控制檯應用程式,起名為CodeFirstEF。我們簡單一點,儘量不參雜到其它技術來進行演示,將學習難度降低到最低。
建立一個控制檯應用程式沒有什麼好說的,這裡想簡單的提一下,使用EF有3種常用的模型,Database-First(資料庫優先)、Model-First(模型優先)、Code-First(程式碼優先)。其中前兩種,資料庫優先和模型優先是比較簡單的兩種模型。可以直接通過VS工具連線資料庫自動生成與資料庫互動的DbContext物件,這種模式有點像我們老早用過的不寫一行程式碼就能自動繫結GridView一樣(雖然有點誇張),雖然極大的提高了使用效率,但是靈活度欠缺。因此這篇部落格,主要演示程式碼優先模型,所以起名為CodeFirstEF。
第二步,在CodeFirstEF中建立一個資料夾Entity,裡面放置兩個模型實體(學生和課程):
學生類上面有個列舉,用以區別性別。namespace CodeFirstEF.Entity { public enum Gender { Female, Male } public class Student { [Key] [DatabaseGeneratedAttribute(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)] public int StudentId { get; set; } public string StudentName { get; set; } public Gender Gender { get; set; } public DateTime? BirthDay { get; set; } public virtual ICollection<Subject> Subjects { get; set; } } }
namespace CodeFirstEF.Entity
{
public class Subject
{
[Key]
[DatabaseGeneratedAttribute(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int SubjectId { get; set; }
public string SubjectName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
}
課程和學生類中都有兩個虛屬性,分別表示學生的課程以及課程有哪些學生。第三步,新增EntityFramework支援。
兩個Entity建好了,下面關鍵的要新增對EF的引用,這裡介紹一個強大的工具NuGet程式包。我們右鍵點選控制檯專案CodeFirstEF,選擇管理NuGet程式包,開啟下列彈出介面,選擇聯機,找到EntityFramework。
選擇安裝EntityFramework。
下載好EntityFramework會彈出視窗。
選擇我接受,很快就會裝好,裝好後如下所示。
點選關閉。這時我們已經為我們的專案添加了EntityFramework支援,可以看到版本號為6,這是目前的最新版本。
第四步,在CodeFirstEF控制檯專案下建立一個資料夾DAL,並建立一個數據庫操作類DataContext。
namespace CodeFirstEF.DAL
{
public class DataContext : DbContext
{
public DataContext(string connectionName) : base(connectionName) { }
public DbSet<Student> Students { get; set; }
public DbSet<Subject> Subjects { get; set; }
}
}
它繼承自DbContext,需要引用名稱空間 using System.Data.Entity。建構函式DbContext有一個引數connectionName,它是用於連線資料庫的名稱。這時我們切換到App.Config配置檔案下,新增connectionStrings節點配置,將資料庫連線的配置新增進去。<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="codeFirstDb" connectionString="Data Source=.;uid=sa;pwd=123456;Database=CodeFirstDb;" providerName="System.Data.SqlClient"/>
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
可以看到裡面的codeFirstDb。好了,這時候讓我們看一下整個專案的結構。
第五步,在Program.cs的Main方法中寫入測試程式碼。
namespace CodeFirstEF
{
class Program
{
static void Main(string[] args)
{
using (var db = new DataContext("codeFirstDb"))
{
//新增學生guwei4037
if (!db.Students.Any(x => x.StudentName == "guwei4037"))
{
db.Students.Add(new Student()
{
StudentName = "guwei4037",
Gender = Gender.Male,
BirthDay = new DateTime(1984, 11, 25),
});
}
//新增課程
if (!db.Subjects.Any(x => x.SubjectName == "English" || x.SubjectName == "Mathmatics" || x.SubjectName == "Computer"))
{
db.Subjects.AddRange(new Subject[]
{
new Subject()
{
SubjectName="English",
},
new Subject()
{
SubjectName="Mathmatics",
},
new Subject()
{
SubjectName="Computer",
}
});
}
//找到guwei4037這個學生
Student student = db.Students.FirstOrDefault(x => x.StudentName == "guwei4037");
//找到數學和英語這兩門課程
List<Subject> subjects = db.Subjects.Where(x => x.SubjectName == "Mathmatics" || x.SubjectName == "English").ToList();
//給學生新增課程
foreach (Subject subject in subjects)
{
student.Subjects.Add(subject);
}
//讓課程知道有哪些學生選擇了它
foreach (Subject subject in subjects)
{
subject.Students.Add(student);
}
//刪除guwei4037這個學生其中的數學這門課程
student.Subjects.Remove(db.Subjects.FirstOrDefault(x => x.SubjectName == "Mathmatics"));
//儲存上述操作的結果
db.SaveChanges();
}
}
}
}
很簡單,註釋也很清晰。執行一下整個控制檯專案,沒有報錯說明程式執行成功了。我們進資料庫檢視一下執行的情況。
這裡我們也可以利用VS工具來檢視,無須開啟SQL Server。
我們看到,EF替我們自動建立了資料庫CodeFirstDb,並且為我們建立了一張中間表,而且將資料都插入到了相應表中。
怎麼樣,EF相當強大吧?而且非常簡單好用,讓你寫程式碼有非常“爽”的感覺。真正的面向物件程式設計就是這麼簡單,不用再學習額外的SQL程式設計了。