說明:個人感覺在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。
在本篇講述的ADO.NET Entity Framework(簡稱Entity Framework或者干脆 稱之為EF),在本系列涉及到的幾種ORM框架中Entity Framework出現得最晚,在 自然界往往遵循著這樣一個規律:出現得越晚的生命力越強。特別是編程語言, 新出現的語言往往都是為了克服當前主流語言的不足而出現的,就想同樣是OOP 語言,Java在很多方面就比C++表現優秀,C#又表現得比Java語言一些,這都是 因為新的語言都是在借鑒了現有語言的優點並摒棄它們的不足而產生的。在這一 點上Entity Framework也是如此。
一、准備
向當前項目中添加ADO.NET Entity Framework類,如下圖所示:
點擊“添加”之後如下圖所示:
選擇“從數據庫生成”,然後點擊“下一步”,如下圖所示:
如果已經存在數據庫連接,就從中選擇一個連接,否則就需要新建一個連接 。點擊“新建連接”之後的界面如下:
這其實就是一個配置數據庫連接的界面,填寫正確的數據庫連接之後點擊“ 確定”按鈕,如下圖所示:
選擇需要的表、視圖及存儲過程,並填寫模型的命名空間,之後點擊“ 完成”,這樣就完成了添加ADO.NET Entity Framework模型文件。
雙擊剛才添加的模型文件,就可以在設計視圖中打開,如下圖所示:
我們還可以在設計視圖的下方編輯它的屬性,如下圖所示:
如果以後數據庫結構發生了變化,也可以很容易根據數據庫來刷新模型文件 ,如下圖所示:
至此,我們完成了初步工作,向當前項目中添加了模型文件。
二、編碼
和使用Linq to SQL一樣,在創建edmx文件時自動創建了相關的 實體類代碼,因此我們只需根據業務邏輯編寫對數據庫操作的類即可,代碼如下 :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.EntityClient;
using System.Configuration;
namespace EntityFrameworkDemo
{
/// <summary>
/// 說明:這個類是為了演示.NET中的Entity Framework的用法
/// 作者:周公(周金橋)
/// 日期:2010-05-05
/// </summary>
public class EntityFrameworkCRUD
{
/// <summary>
/// 統計用戶總數
/// </summary>
/// <returns></returns>
public int Count()
{
#region 方法二,使用Linq to Entities
using (AspNetStudyEntities entities = new AspNetStudyEntities())
{
//entities.UserInfo.Count<UserInfo>(item => item.Age > 23);//帶條件查詢
return entities.UserInfo.Count<UserInfo>();
}
#endregion
}
/// <summary>
/// 創建用戶
/// </summary>
/// <param name="info">用 戶實體</param>
/// <returns></returns>
public void Create(UserInfo info)
{
using (AspNetStudyEntities entities = new AspNetStudyEntities())
{
entities.AddToUserInfo(info);
entities.SaveChanges();
}
}
/// <summary>
/// 讀取用戶信息
/// </summary>
/// <param name="userId"> 用戶編號</param>
/// <returns></returns>
public UserInfo Read(int userId)
{
//AspNetStudyEntities entities = new AspNetStudyEntities();
//return entities.UserInfo.First<UserInfo>(item => item.UserID == userId);
方法二,使用EntityKey#region 方法二,使用 EntityKey
using (AspNetStudyEntities entities = new AspNetStudyEntities())
{
EntityKey entityKey = new EntityKey ("AspNetStudyEntities.UserInfo","UserID",userId);
return entities.GetObjectByKey(entityKey) as UserInfo;
}
#endregion
}
/// <summary>
/// 更新用戶信息
/// </summary>
/// <param name="info">用 戶實體</param>
/// <returns></returns>
public void Update(UserInfo info)
{
using (AspNetStudyEntities entities = new AspNetStudyEntities())
{
UserInfo ui = entities.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;
entities.SaveChanges();
}
}
/// <summary>
/// 刪除用戶
/// </summary>
/// <param name="userId"> 用戶編號</param>
/// <returns></returns>
public void Delete(int userId)
{
#region 方法二
using (AspNetStudyEntities entities = new AspNetStudyEntities())
{
UserInfo ui = entities.UserInfo.First<UserInfo>(item => item.UserID == userId);
entities.DeleteObject(ui);
entities.SaveChanges();
}
#endregion
}
/// <summary>
/// 刪除用戶
/// </summary>
/// <param name="userId"> 用戶實體</param>
/// <returns></returns>
public void Delete(UserInfo info)
{
using (AspNetStudyEntities entities = new AspNetStudyEntities())
{
UserInfo ui = entities.UserInfo.First<UserInfo>(item => item.UserID == info.UserID);
entities.DeleteObject(ui);
entities.SaveChanges();
}
}
/// <summary>
/// 獲取用戶表中編號最大的用戶
/// </summary>
/// <returns></returns>
public int GetMaxUserId()
{
using (AspNetStudyEntities entities = new AspNetStudyEntities())
{
int userId=entities.UserInfo.Max<UserInfo>(item => item.UserID);
return userId;
}
}
}
}
三、單元測試代碼
為了照顧很多仍在使用NUnit作為單元測試工具的開發人員的習慣,我們的單 元測試代碼針對NUnit2.5.3,代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using EntityFrameworkDemo;
namespace NUnitTest
{
[TestFixture]
class EntityFrameworkTest
{
private EntityFrameworkCRUD instance = null;
[SetUp]
public void Initialize()
{
instance = new EntityFrameworkCRUD();
}
[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("userid={0},username={1}", info.UserID, info.UserName);
instance.Delete (info);
}
}
}
上面的代碼在NUnit2.5.3中測試通過。
四、總結
同樣作為微軟的 ORM框架,我覺得Linq to SQL更像一個探路的,試探一下大 家對官方ORM的反應,正因為如此Linq to SQL在對數據庫種類的支持上僅僅支持 SQL Server,但是作為一個產品系列Linq to XML、Linq to SQL讓大家對XML和 數據庫的訪問更加方便了,因此得到了很多開發人員的追捧。而ADO.NET Entity Framework由於出現較晚的原因(在.NET Framework SP1及更高版本中支持), 所以對Linq to SQL的某些不足進行了改進,並且還提供了Linq to Entities技 術。
在ADO.NET Entity Framework提供了四種訪問數據庫的方法:Linq to Entitiess、Entity SQL、EntityKey及直接對數據庫用SQL語句查詢,多種訪問 方法為我們在不同場合下使用提供了方便,需要特別說明的是Entity SQL目前僅 支持SELECT操作,而不支持CREATE/DELETE/UPDATE操作,具體出處見:How Entity SQL Differs from Transact-SQL
從性能上考慮,對於擁有豐富數據庫開發經驗的程序員來說,使用ORM確實會 比直接使用SQL語句要性能低些,因為不管是Linq to Entitiess還是Entity SQL 都最終會轉換成SQL交給ADO.NET執行,肯定比直接使用ADO.NET執行SQL語句要慢 。對於沒有經驗的開發人員來說,它們之間差別不大 ——反正都是很慢。
從開發速度和靈活性上考慮,使用ORM框架比使用ADO.NET開發速度要高,而 且假如數據庫發生了變化對代碼的影響也較小(盡管沒有人會頻繁改變數據庫折 騰自己,但是在開發階段更改數據庫的可能性仍是存在的,畢竟不可能讓設計做 到百分之百完美),當然對數據庫操作的靈活性是 ADO.NET勝出了。
從可維護性上考慮,使用ADO.NET因為靈活性大所以不同的程序員實現同樣的 功能可能代碼相差較大,而使用同一種 ORM框架時這種代碼上的差別不會太大, 便於維護。
以前我一直拒絕ASP.NET MVC,而一直使用自己習慣的三層架構開發模式,在 網站前台盡可能少的使用服務器控件更多地是采用模板替換法或者生成靜態頁面 、在後台則盡可能使用服務器控件,這麼做的目的是出於前台訪問的用戶數大、 後台訪問用戶數少所以在前台盡可能使用運行高效的方式而在後台盡可能采取高 效的開發方式。直到去年的時候維護別人的一個項目,我才逐漸體會到MVC的好 處,那就是控制起來靈活並且維護起來相對方便一些。
如果僅僅追求運行效率,那麼只有機器語言就足夠了;如果除此之外還希望 能兼顧一下開發效率,那麼C足夠了;如果除此之外還希望兼顧一下代碼重用, 那麼C++也能滿足了;如果除此之外,還希望更健壯避免直接操作內存,那麼 Java也是可以的;如果除此之外還希望更多更靈活的功能,那麼C#是可以 的......
總之,每一種後出現的新生事物都是借鑒了它的前輩成功之處的,特別是在 前輩的最成功之處,但是由於在某些地方太過關注,所以它在其它方面又會有一 些不足,但是這些不足又是可以通過其它方式相對較容易解決的,甚至在某些情 況下根本可以忽略。比如在中國大部分的程序員不用太關注是否提供跨平台支持 ,因為中國大部分公司都是用的Windows;在中國的相當部分程序員不用太關注 性能問題,因為他們開發的產品從投入使用到最後停止運行過程中產生的數據單 表記錄超過百萬的都不多。
如何選擇合適的技術,取決於我們隊將要運行的環境的判斷,這來自於經驗 分析。
出處http://zhoufoxcn.blog.51cto.com/792419/313309