本系列承接入門系列內容,獨立成章。LINQ to SQL 主要解決「資料 ≠ 物件」的阻抗失配問題,建立資料表與類別的一對一映射關係,降低開發門檻,取代傳統 ADO.NET 手工組裝 SQL 與物件映射的繁瑣流程。
LINQ(Language Integrated Query)包含三大塊:

DBML(Database Markup Language)是 XML 格式的中介描述檔,用於橋接資料庫結構與程式碼產生(支援 C#/VB.NET 差異)。流程為:
Database → DBML → Code
使用 sqlmetal 命令列工具產生 DBML:
sqlmetal /server:YourServer /database:Northwind /dbml:YourDbml.dbml
再由 DBML 產生程式碼:
sqlmetal YourDbml.dbml /code:nwind.cs
OR Designer(Visual Studio 視覺化工具)實際上操作的就是 DBML 檔。部分進階映射(如繼承)需手動修改 DBML。
資料間基本關聯僅兩種:1:1 與 1:M。以 Northwind 範例資料庫的 Orders(訂單)與 Order Details(訂單明細)為例,關係為 1:M。
[Table(Name="Orders")]
public partial class Order : INotifyPropertyChanging, INotifyPropertyChanged {
[Association(Name="Order_OrderDetail", Storage="_OrderDetails", OtherKey="OrderID")]
public EntitySet<OrderDetail> OrderDetails {
get { return this._OrderDetails; }
set { this._OrderDetails.Assign(value); }
}
}
EntitySet<TEntity> 實作 IList、ICollection<T>、IEnumerable<T> 等介面,代表「多」端集合。
[Table(Name="Order Details")]
public partial class OrderDetail : INotifyPropertyChanging, INotifyPropertyChanged {
private EntityRef<Order> _Order;
[Association(Name="Order_OrderDetail", Storage="_Order", ThisKey="OrderID", IsForeignKey=true)]
public Order Order {
get { return this._Order.Entity; }
set {
// 雙向同步邏輯:更新雙端導覽屬性與外鍵值
Order previousValue = this._Order.Entity;
if (previousValue != value || !this._Order.HasLoadedOrAssignedValue) {
this.SendPropertyChanging();
if (previousValue != null) {
this._Order.Entity = null;
previousValue.OrderDetails.Remove(this);
}
this._Order.Entity = value;
if (value != null) {
value.OrderDetails.Add(this);
this._OrderID = value.OrderID;
} else this._OrderID = default(int);
this.SendPropertyChanged("Order");
}
}
}
}
EntityRef<T> 延遲載入單一參考物件,.Entity 屬性觸發載入。
EntitySet<T>(集合),Many 端用 EntityRef<T>(單一參考)EntityRef<T>導覽屬性的型別差異直接反映關聯主體的角色不同。