LINQ語言集成查詢是微軟用於抗衡競爭對手,改進現有開發模式下面向數據庫操作問題的一個種全新體系架構。它的出現,解決了面向對象開發中由數據庫操作引起的先天性的瓶頸,使得面向對象和數據庫完美結合,程序員不再受限於復雜的SQL腳本,而可以一種近乎完美的方式來搭建自己的面向對象型軟件 系統,這種方式就是將數據完全對象化,將SQL語句封裝到底層,由framework來完成,程序員 只需面向數據庫對象來編程,從另一種意義上來說,是把數據也程序化了。
LINQ的這種開發模式也改變了系統架構的搭建方式,在以往的系統中,數據訪問層DAL 要訪問數據字段,業務邏輯層BLL要得到數據都需要通過數據模型層Model來處理,而LINQ和 VS2008為我們帶來了一種全新的自動化方式生成數據模型層,這就是dbml(Database Mark Language。數據庫描述語言,是一種xml格式的文檔,用來描述數據庫),有了它我們就不需要 去找那些第三方的代碼生成工具,只需要把數據表拖拽到設計器中,如下圖所示,DONET便為我 們做好了一切。
完成拖拽操作後,VS會自動生成一個數據模型層的dbml文件和相關的類文件。這樣我們省去 了數據模型層的搭建,系統的架構也就有所不同,以下用一個例子簡單的講一下該架構模型。
為了完成這個架構,我們首先要創建一個WEB APPLICATION項目,在新建項目窗口選擇 “ASP.NET WEB應用程序”,為它取一個名字,並確定。
接下來,在解決方案資源管理器中再添加一個類庫項目,取名為DAL,如下圖:
再使用同樣的方法在解決方案資源管理器中添加一個類庫項目,取名為BLL,這樣我們的基 礎架構搭建完成,此時我們的解決方案資源管理器應該是如下結構。
此時,我們先從DAL項目入手,在DAL項目中,添加一個LINQ TO SQL類,取名為Northwind( 為了方便起見,此項目使用SQL SERVER2005中的Northwind示例數據庫),雙擊新建立的 Northwind.dbml文件,然後打開“服務器資源管理器”,建立與數據的連接,並從Northwind數 據庫中,將Employees表拖拽到Northwind.dbml文件的可視化設計器中。
初始的Northwind.dbml文件代碼如下:
#pragma warning disable 1591
//--------------------------------------
----------------------------------------
//
// 此代碼由
工具生成。
// 運行時版本:2.0.50727.3053
//
// 對此文件的更改可能會
導致不正確的行為,並且如果
// 重新生成代碼,這些更改將會丟失。
//
//-----------------------------------------------------------------
-------------
namespace DAl
{
using System.Data.Linq;
using
System.Data.Linq.Mapping;
using System.Data;
using
System.Collections.Generic;
using System.Reflection;
using
System.Linq;
using System.Linq.Expressions;
using
System.ComponentModel;
using System;
[System.Data.Linq.Mapping.DatabaseAttribute(Name="Northwind")]
public
partial class NorthwindDataContext : System.Data.Linq.DataContext
{
private static System.Data.Linq.Mapping.MappingSource mappingSource = new
AttributeMappingSource();
#region Extensibility Method Definitions
partial void OnCreated();
partial void InsertEmployees(Employees
instance);
partial void UpdateEmployees(Employees instance);
partial
void DeleteEmployees(Employees instance);
#endregion
public
NorthwindDataContext() :
base
(global::DAL.Properties.Settings.Default.NorthwindConnectionString, mappingSource)
{
OnCreated();
}
public NorthwindDataContext(string
connection) :
base(connection, mappingSource)
{
OnCreated();
}
public NorthwindDataContext(System.Data.IDbConnection connection) :
base(connection, mappingSource)
{
OnCreated();
}
public NorthwindDataContext(string connection,
System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection,
mappingSource)
{
OnCreated();
}
public
NorthwindDataContext(System.Data.IDbConnection connection,
System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection,
mappingSource)
{
OnCreated();
}
public
System.Data.Linq.Table Employees
{
get
{
return
this.GetTable();
}
}
}
[Table
(Name="dbo.Employees")]
public partial class Employees :
INotifyPropertyChanging, INotifyPropertyChanged
{
private static
PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs
(String.Empty);
private int _EmployeeID;
private string
_LastName;
private string _FirstName;
private string
_Title;
private string _TitleOfCourtesy;
private
System.Nullable
private
System.Nullable
private string _Address;
private string _City;
private string _Region;
private
string _PostalCode;
private string _Country;
private string
_HomePhone;
private string _Extension;
private
System.Data.Linq.Binary _Photo;
private string _Notes;
private System.Nullable _ReportsTo;
private string _PhotoPath;
#region Extensibility Method Definitions
partial void OnLoaded
();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnEmployeeIDChanging(int value);
partial void OnEmployeeIDChanged();
partial void OnLastNameChanging(string
value);
partial void OnLastNameChanged();
partial void
OnFirstNameChanging(string value);
partial void OnFirstNameChanged();
partial void OnTitleChanging(string value);
partial void OnTitleChanged
();
partial void OnTitleOfCourtesyChanging(string value);
partial
void OnTitleOfCourtesyChanged();
partial void OnBirthDateChanging
(System.Nullable
partial void OnBirthDateChanged
();
partial void OnHireDateChanging(System.Nullable
value);
partial void OnHireDateChanged();
partial void
OnAddressChanging(string value);
partial void OnAddressChanged();
partial void OnCityChanging(string value);
partial void OnCityChanged();
partial void OnRegionChanging(string value);
partial void
OnRegionChanged();
partial void OnPostalCodeChanging(string value);
partial void OnPostalCodeChanged();
partial void OnCountryChanging(string
value);
partial void OnCountryChanged();
partial void
OnHomePhoneChanging(string value);
partial void OnHomePhoneChanged();
partial void OnExtensionChanging(string value);
partial void
OnExtensionChanged();
partial void OnPhotoChanging(System.Data.Linq.Binary
value);
partial void OnPhotoChanged();
partial void OnNotesChanging
(string value);
partial void OnNotesChanged();
partial void
OnReportsToChanging(System.Nullable value);
partial void
OnReportsToChanged();
partial void OnPhotoPathChanging(string value);
partial void OnPhotoPathChanged();
#endregion
public Employees()
{
OnCreated();
}
[Column(Storage="_EmployeeID",
DbType="Int NOT NULL", IsPrimaryKey=true)]
public int EmployeeID
{
get
{
return this._EmployeeID;
}
set
{
if
((this._EmployeeID != value))
{
this.OnEmployeeIDChanging(value);
this.SendPropertyChanging();
this._EmployeeID = value;
this.SendPropertyChanged("EmployeeID");
this.OnEmployeeIDChanged();
}
}
}
[Column(Storage="_LastName", DbType="NVarChar(20) NOt
NULL", CanBeNull=false)]
public string LastName
{
get
{
return this._LastName;
}
set
{
if ((this._LastName != value))
{
this.OnLastNameChanging(value);
this.SendPropertyChanging();
this._LastName = value;
this.SendPropertyChanged("LastName");
this.OnLastNameChanged();
}
}
}
[Column
(Storage="_FirstName", DbType="NVarChar(10) NOT NULL", CanBeNull=false)]
public string FirstName
{
get
{
return this._FirstName;
}
set
{
if ((this._FirstName != value))
{
this.OnFirstNameChanging(value);
this.SendPropertyChanging();
this._FirstName = value;
this.SendPropertyChanged("FirstName");
this.OnFirstNameChanged();
}
}
}
[Column
(Storage="_Title", DbType="NVarChar(30)")]
public string Title
{
get
{
return this._Title;
}
set
{
if ((this._Title
!= value))
{
this.OnTitleChanging(value);
this.SendPropertyChanging();
this._Title = value;
this.SendPropertyChanged("Title");
this.OnTitleChanged();
}
}
}
[Column(Storage="_TitleOfCourtesy", DbType="NVarChar(25)")]
public string TitleOfCourtesy
{
get
{
return
this._TitleOfCourtesy;
}
set
{
if ((this._TitleOfCourtesy !=
value))
{
this.OnTitleOfCourtesyChanging(value);
this.SendPropertyChanging();
this._TitleOfCourtesy = value;
this.SendPropertyChanged("TitleOfCourtesy");
this.OnTitleOfCourtesyChanged
();
}
}
}
[Column(Storage="_BirthDate",
DbType="DateTime")]
public System.Nullable
{
get
{
return this._BirthDate;
}
set
{
if
((this._BirthDate != value))
{
this.OnBirthDateChanging(value);
this.SendPropertyChanging();
this._BirthDate = value;
this.SendPropertyChanged("BirthDate");
this.OnBirthDateChanged();
}
}
}
[Column(Storage="_HireDate", DbType="DateTime")]
public System.Nullable
{
get
{
return
this._HireDate;
}
set
{
if ((this._HireDate != value))
{
this.OnHireDateChanging(value);
this.SendPropertyChanging();
this._HireDate = value;
this.SendPropertyChanged("HireDate");
this.OnHireDateChanged();
}
}
}
[Column
(Storage="_Address", DbType="NVarChar(60)")]
public string Address
{
get
{
return this._Address;
}
set
{
if
((this._Address != value))
{
this.OnAddressChanging(value);
this.SendPropertyChanging();
this._Address = value;
this.SendPropertyChanged("Address");
this.OnAddressChanged();
}
}
}
[Column(Storage="_City", DbType="NVarChar(15)")]
public
string City
{
get
{
return this._City;
}
set
{
if
((this._City != value))
{
this.OnCityChanging(value);
this.SendPropertyChanging();
this._City = value;
this.SendPropertyChanged("City");
this.OnCityChanged();
}
}
}
[Column(Storage="_Region", DbType="NVarChar(15)")]
public string
Region
{
get
{
return this._Region;
}
set
{
if
((this._Region != value))
{
this.OnRegionChanging(value);
this.SendPropertyChanging();
this._Region = value;
this.SendPropertyChanged("Region");
this.OnRegionChanged();
}
}
}
[Column(Storage="_PostalCode", DbType="NVarChar(10)")]
public
string PostalCode
{
get
{
return this._PostalCode;
}
set
{
if ((this._PostalCode != value))
{
this.OnPostalCodeChanging(value);
this.SendPropertyChanging();
this._PostalCode = value;
this.SendPropertyChanged("PostalCode");
this.OnPostalCodeChanged();
}
}
}
[Column
(Storage="_Country", DbType="NVarChar(15)")]
public string Country
{
get
{
return this._Country;
}
set
{
if
((this._Country != value))
{
this.OnCountryChanging(value);
this.SendPropertyChanging();
this._Country = value;
this.SendPropertyChanged("Country");
this.OnCountryChanged();
}
}
}
[Column(Storage="_HomePhone", DbType="NVarChar(24)")]
public string HomePhone
{
get
{
return this._HomePhone;
}
set
{
if ((this._HomePhone != value))
{
this.OnHomePhoneChanging(value);
this.SendPropertyChanging();
this._HomePhone = value;
this.SendPropertyChanged("HomePhone");
this.OnHomePhoneChanged();
}
}
}
[Column
(Storage="_Extension", DbType="NVarChar(4)")]
public string Extension
{
get
{
return this._Extension;
}
set
{
if
((this._Extension != value))
{
this.OnExtensionChanging(value);
this.SendPropertyChanging();
this._Extension = value;
this.SendPropertyChanged("Extension");
this.OnExtensionChanged();
}
}
}
[Column(Storage="_Photo", DbType="Image",
UpdateCheck=UpdateCheck.Never)]
public System.Data.Linq.Binary Photo
{
get
{
return this._Photo;
}
set
{
if ((this._Photo
!= value))
{
this.OnPhotoChanging(value);
this.SendPropertyChanging();
this._Photo = value;
this.SendPropertyChanged("Photo");
this.OnPhotoChanged();
}
}
}
[Column(Storage="_Notes", DbType="NText",
UpdateCheck=UpdateCheck.Never)]
public string Notes
{
get
{
return this._Notes;
}
set
{
if ((this._Notes != value))
{
this.OnNotesChanging(value);
this.SendPropertyChanging();
this._Notes = value;
this.SendPropertyChanged("Notes");
this.OnNotesChanged();
}
}
}
[Column
(Storage="_ReportsTo", DbType="Int")]
public System.Nullable
ReportsTo
{
get
{
return this._ReportsTo;
}
set
{
if ((this._ReportsTo != value))
{
this.OnReportsToChanging(value);
this.SendPropertyChanging();
this._ReportsTo = value;
this.SendPropertyChanged("ReportsTo");
this.OnReportsToChanged();
}
}
}
[Column(Storage="_PhotoPath", DbType="NVarChar(255)")]
public string PhotoPath
{
get
{
return this._PhotoPath;
}
set
{
if ((this._PhotoPath != value))
{
this.OnPhotoPathChanging(value);
this.SendPropertyChanging();
this._PhotoPath = value;
this.SendPropertyChanged("PhotoPath");
this.OnPhotoPathChanged();
}
}
}
public event
PropertyChangingEventHandler PropertyChanging;
public event
PropertyChangedEventHandler PropertyChanged;
protected virtual void
SendPropertyChanging()
{
if ((this.PropertyChanging != null))
{
this.PropertyChanging(this, emptyChangingEventArgs);
}
}
protected virtual void SendPropertyChanged(String propertyName)
{
if
((this.PropertyChanged != null))
{
this.PropertyChanged(this, new
PropertyChangedEventArgs(propertyName));
}
}
}
}
#pragma
warning restore 1591
從中可以看到,這裡本質上就是以前的數據模型層,將數據整個對象化了,為了層之間的訪 問方便,我們將改類的命名空間改為Auto.DAL,並將NorthwindDataContent類的第一個構造函 數代碼修改如下,這樣修改主要是為了統一數據庫連接字符串的位置,因為dbml文件在生成後 會附帶生成一個app.config文件,用來存放連接字符串,而我們要把連接字符串統一放到 web.config中。(要訪問web.config文件,需要為DAL項目添加對System.Configuration的應用 )
public NorthwindDataContext() :
base
(ConfigurationManager.ConnectionStrings
["NorthwindConnectionString"].ConnectionString, mappingSource)
{
OnCreated
();
}
完成前面的操作以後,開始建立數據訪問層的類文件,這時,先在 DAL項目下添加一個類文件,取名為DALEmployees.cs,其代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Auto.DAl
{
public class DALEmployees
{
///
/// VS自動生成的數據模型
///
NorthwindDataContext db = new NorthwindDataContext();
///
/// 根據條件獲取數據列表方法
///
/// 城 市地址
/// 獲取的Employees數據列表
public IQueryable GetList(string strCity)
{
//根據城市地質,通過LINQ返 回數據
return from p in db.Employees
where p.City == strCity
select p;
}
}
}
這個數據訪問層中只建立了一個用來根據城市地址獲取Employee數據的方法,它內部執行一 段LINQ,返回一個IQueryable型的結果,由於LINQ後期編譯的特性,這個結果只有在程序運行 後才會返回數據集。
接著,建立業務邏輯層,在BLL項目中,添加一個類文件,取名為BLLEmployees.cs,其代碼 如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Auto.DAL;
namespace Auto.BLl
{
public class BLLEmployees
{
///
/// 通過城市名獲得Employee數據
///
/// 城市名
/// 數據 結果
public IQueryable GetList(string strCity)
{
DALEmployees de=new DALEmployees();
//調用數據訪問層的方法
return de.GetList(strCity);
}
}
}
這段代碼完成了業務邏輯層的定義,建立了一個和數據訪問層的同名方法GetList,用來傳 送城市名稱參數。最後,在WEB Application項目中,添加對BLL層的應用,並在Default.aspx 頁面中添加一個GridView控件用來顯示數據,Default.aspx.cs的代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Auto.BLL;
namespace WebApplication2
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GetList("London");
}}
///
/// 根據城市獲取數據
///
///
城市名稱 private void GetList(string strCity)
{
//執行業務邏輯層的方法
BLLEmployees bl = new BLLEmployees();
//綁 定到GridView1控件
GridView1.DataSource = bl.GetList (strCity);
GridView1.DataBind();
}}}
完成後,執行程序,便可得到相關數據,整個程序的結構如下:
總結:實際上,這個基於LINQ的架構是將數據模型層和數據訪問層整合到一個項目中,它的 特點就是開發快速,效率高,可以很方便的幫你完成數據模型的搭建,並且也便於後期修改, 當數據表發生變動時,只選要修改dbml文件就可以了。但這個架構裡有些地方還是不大完善, 例如城市數據作為參數,應該也是以數據模型的方式來傳送,但這裡僅是按字符串傳遞,這樣 不利於數據的封裝和安全。因此還需要在此處改進。總體來說,比以往的三層架構結構更加清 晰了,如果再結合ASP.NET MVC架構來使用,就更加完美了。