說明:個人感覺在Java領域大型開發都離不了ORM的身影,所謂的SSH就是 Spring+Struts+Hibernate,除了在學習基礎知識的時候被告知可以使用JDBC操 作數據庫之外,大量的書籍中都是講述使用Hibernate這個ORM工具來操作數據。 在.NET中操作數據庫的方式有多種,除了最直接的方式就是使用ADO.NET之外, 還可以使用NHibernate這個Hibernate在.NET中的實現ORM,如果你對第三方的 ORM 持懷疑態度,你還可以使用來自微軟的實現、根正苗紅的Linq或者 EntityFramework。
大部分從早期就開始使用.NET開發的程序員可能對ADO.NET有種迷戀,使用 ADO.NET可以充分將我們早期的SQL知識發揮得淋漓盡致,並且出於對性能的考慮 ,有些人對.NET中的ORM 還保持一種觀望態度,包括我自己也是這種態度。不過 即使在實際開發中不用,並不代表我們不能去了解和比較這些技術,任何事物的 出現和消亡總有其原因的,我們可以了解它們的優點和長處。所以本人抽出了幾 個周末的時間分別用ADO.NET、NHibernate、Linq和EntityFramework來實現對數 據庫單表數據的創建、讀取、更新和刪除操作,也就是所謂的CRUD (C:Create/R:Read/U:Update/D:Delete)。
通過實現相同功能的比較,大家自己判斷那種方式更適合自己。需要說明的 是,如果在VS2008中使用EntityFramework就需要安裝 VS2008SP1。
語言集成查詢 (LINQ) 是 Visual Studio 2008 中的一組功能,可為 C# 和 Visual Basic 語言語法提供強大的查詢功能。LINQ 引入了標准的、易於學習的 查詢和更新數據模式,可以對其技術進行擴展以支持幾乎任何類型的數據存儲。 Visual Studio 2008 包含 LINQ 提供程序的程序集,這些程序集支持將 LINQ 與 .NET Framework 集合、SQL Server 數據庫、ADO.NET 數據集和 XML 文檔一 起使用。
在本篇講述利用Linq實現對數據庫的CRUD功能,也就是Linq to SQL,需要說 明的是Linq to SQL只支持SQL Server數據庫,Linq to SQL只是Linq的一部分功 能。
用Linq to SQL來操作數據庫確實比使用NHibernate在操作上要方便得多,通 過下面的操作讀者也會體會得到,畢竟這個是微軟官方的東東,微微支持的力度 自然要大些。
一、准備
首先,向項目中添加Linq To SQL的類,如下圖所示:
在名稱一欄中填寫較友好的名字之後,然後項目中就會增加一個後綴為dbml 的文件,雙擊這個文件就會進入設計視圖,如下圖所示:
在服務器資源管理中找到相應的數據庫連接,依次點開之後就可以將數據庫 中的表拖到dbml設計器上。如果讀者界面上沒有服務器資源管理器可以使用 CTRL+ALT+S組合鍵將其調出來。如果沒有數據庫連接,可以按照下面的步驟進行 ,在服務器資源管理器中的“數據連接”—— “添加連接”,出現如下界面:
在上面的界面中依次填寫好數據庫、用戶名和密碼及要連接的庫名之 後,點擊確定,這樣在服務器資源管理器中就增加了一個數據庫連接,展開之後 如下圖所示:
拖拽一個表到dbml上就會自動生成這個表的實體類,如下圖所示:
也許有人會思考這個類的定義在哪裡,可以告訴你的是這個類的定義 在這個dbml文件對應的cs文件中(dbml文件名.designer.cs這種形式),如下圖 所示:
有些這些之後我們就可以動手編碼實現對數據庫進行CRUD操作了。
二 、編碼
由於在dbml文件中已經存在了DataContext和UserInfo表對應的 UserInfo實體類,所以我們僅僅需要編寫對數據庫操作的類就可以了。編寫的代 碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data.Linq;
using System.Configuration;
namespace LinqDemo
{
/// <summary>
/// 說明:這個類是為了演示.NET中的Linq to SQL 的用法
/// 作者:周公(周金橋)
/// 日期:2010-03-01
/// </summary>
public class LinqCRUD
{
/// <summary>
/// 統計用戶總數
/// </summary>
/// <returns></returns>
public int Count()
{
方法一#region 方法一
//使用 SqlConnection來實例化DataContext對象
SqlConnection connection = new SqlConnection (ConfigurationManager.ConnectionStrings ["LinqDemo.Properties.Settings.AspNetStudyConnectionString"].Connectio nString);
DataContext context = new DataContext(connection);
IEnumerable<int> collection = context.ExecuteQuery<int>("select count(1) from UserInfo");
int count = collection.ElementAt<int>(0);
return count;
#endregion
方法二#region 方法二
//UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();
////return context.UserInfo.Count<UserInfo>(item => item.Age > 23);//帶條件統計
//return context.UserInfo.Count<UserInfo>();
#endregion
}
/// <summary>
/// 創建用戶
/// </summary>
/// <param name="info">用 戶實體</param>
/// <returns></returns>
public void Create(UserInfo info)
{
UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();
context.UserInfo.InsertOnSubmit(info);
context.SubmitChanges();
}
/// <summary>
/// 讀取用戶信息
/// </summary>
/// <param name="userId"> 用戶編號</param>
/// <returns></returns>
public UserInfo Read(int userId)
{
UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();
context.Log = Console.Out;
var query = from item in context.UserInfo
where item.UserID == userId
select item;
return query.First<UserInfo>();
}
/// <summary>
/// 更新用戶信息
/// </summary>
/// <param name="info">用 戶實體</param>
/// <returns></returns>
public void Update(UserInfo info)
{
UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();
UserInfo ui = context.UserInfo.First<UserInfo>(item => item.UserID == info.UserID);
ui.Age = info.Age;
ui.Email = info.Email;
ui.Mobile = info.Mobile;
ui.Phone = info.Phone;
ui.RealName = info.RealName;
ui.Sex = info.Sex;
ui.UserName = info.UserName;
context.SubmitChanges();
}
/// <summary>
/// 刪除用戶
/// </summary>
/// <param name="userId"> 用戶編號</param>
/// <returns></returns>
public void Delete(int userId)
{
方法一#region 方法一
//UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();
//context.ExecuteCommand("delete from UserInfo where UserId=" + userId);
#endregion
方法二#region 方法二
UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();
UserInfo ui = context.UserInfo.First<UserInfo>(item => item.UserID == userId);
context.UserInfo.DeleteOnSubmit(ui);
context.SubmitChanges();
#endregion
}
/// <summary>
/// 刪除用戶
/// </summary>
/// <param name="userId"> 用戶實體</param>
/// <returns></returns>
public void Delete(UserInfo info)
{
UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();
var userList = from Users
in context.UserInfo
where Users.UserID == info.UserID
select Users;
foreach (var user in userList)
{
context.UserInfo.DeleteOnSubmit(user);
}
//context.UserInfo.DeleteOnSubmit(userList.First<UserInfo> ());
//注意下面的寫法 是錯誤的
// context.UserInfo.DeleteOnSubmit(info);
context.SubmitChanges();
}
/// <summary>
/// 獲取用戶表中編號最大的用戶
/// </summary>
/// <returns></returns>
public int GetMaxUserId()
{
UserInfoDataClassesDataContext context = new UserInfoDataClassesDataContext();
int userId=context.UserInfo.Max<UserInfo>(item => item.UserID);
return userId;
}
}
}
說明,在上面的代碼中每個方法的第一句都是實例化一個叫 UserInfoDataClassesDataContext的類,這個類我們並沒有編寫,但是奇怪的是 上面的代碼居然能編譯通過,這是為什麼呢?原來秘密還是在那個dbml文件中, 這個類在dbml的設計文件中的定義如下:
[System.Data.Linq.Mapping.DatabaseAttribute (Name="AspNetStudy")]
public partial class UserInfoDataClassesDataContext : System.Data.Linq.DataContext
{
//.....省略其它代碼
}
可以看出UserInfoDataClassesDataContext是繼承DataContext的,這個 DataContext在MSDN中的定義為:
DataContext 是通過數據庫連接映射的所有實體的源。它會跟蹤您對所有檢 索到的實體所做的更改,並且保留一個“標識緩存”,該緩存確保使用同一對象 實例表示多次檢索到的實體。
也就是我們用DataContext來與數據庫進行交互,DataContext會根據上下文 環境來決定如何與數據庫交互,正因為如此,所以我們用Linq to SQL的代碼才 如此簡單!
三、單元測試代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using LinqDemo;
namespace NUnitTest
{
[TestFixture]
public class LinqTest
{
private LinqCRUD instance = null;
[SetUp]
public void Initialize()
{
instance = new LinqCRUD();
}
[Test]
/// <summary>
/// 統計用戶總數
/// </summary>
/// <returns></returns>
public void Count()
{
Assert.Greater (instance.Count(), 0);
}
[Test]
/// <summary>
/// 創建用戶
/// </summary>
/// <param name="info">用 戶實體</param>
/// <returns></returns>
public void Create()
{
UserInfo info = new UserInfo()
{
Age = 12,
Email = "[email protected]",
Mobile = "13812345678",
Phone = "01012345678",
RealName = "測試" + DateTime.Now.Millisecond.ToString(),
Sex = true,
UserName = "zhoufoxcn" + DateTime.Now.Millisecond.ToString()
};
instance.Create (info);
}
[Test]
/// <summary>
/// 讀取用戶信息
/// </summary>
/// <param name="userId"> 用戶編號</param>
/// <returns></returns>
public void Read()
{
UserInfo info = instance.Read(1);
Assert.NotNull (info);
}
[Test]
/// <summary>
/// 更新用戶信息
/// </summary>
/// <param name="info">用 戶實體</param>
/// <returns></returns>
public void Update()
{
UserInfo info = instance.Read(1);
info.RealName = "測試" + DateTime.Now.Millisecond.ToString();
instance.Update (info);
}
[Test]
/// <summary>
/// 刪除用戶
/// </summary>
/// <param name="userId"> 用戶編號</param>
/// <returns></returns>
public void DeleteByID()
{
int userId = instance.GetMaxUserId();
instance.Delete (userId);
}
[Test]
/// <summary>
/// 刪除用戶
/// </summary>
/// <param name="userId"> 用戶實體</param>
/// <returns></returns>
public void Delete()
{
int userId = instance.GetMaxUserId();
UserInfo info = instance.Read(userId);
//Console.WriteLine("MaxUserId=" + userId);
instance.Delete (info);
}
}
}
上面的代碼在NUnit2.5.3中測試通過。
四、總結
NHibernate 與ADO.NET相比開發更簡單,應對數據庫的變化更靈活,而Linq to SQL比NHibernate更方便應對數據庫變化,開發效率也高,使用Linq to SQL 後我們僅需要編寫一個類就足夠了,比較遺憾的是Linq to SQL只支持SQL Server,所以很多人都在使用Entity Framework這個ORM框架了。
出處http://zhoufoxcn.blog.51cto.com/792419/293966