static修飾符我們不會陌生,它代表靜態,可以修飾你的類,方法,字段和屬性等等,今天主要說一個為靜態字段加ThreadStatic特性會給程序代來什么樣的變化。靜態字段static field,我更習慣稱它為“類的字段”,即它與類的具體實例無關,對於所有線程里,它的值都是一個,即它的唯一性。
如代碼:
class Instance
{ static DataContext context=new LinqToSql(conn);
protected static DataContext {get{return context;}}
}
上面的代碼中,context為靜態字段,它的值在所有線程中都是一樣的,換名話說,在多個用戶訪問一個頁面里,得到它的值都是一樣的。
上面代碼是一個linq to sql實現DAL層時的一個基類,它向子類公開一個數據上下文,在所有用戶訪問里(所有線程中)其值(內存地址)都是一樣的,而在LINQTOSQL架構中,這個靜態數據上下文在實現開發中會出現很多問題,所以,官方不推薦使用。
但是,如果我們引入ThreadStatic之后,結果就不同了,當字段被ThreadStatic特性修飾后,它的值在每個線程中都是不同的,即每個線程對static字段都會重新分配內存空間,就當然於一次new操作,這樣一來,由於static字段所產生的問題也就沒有了,這種static數據上下文是可以被接受的。
internal class DbFactory { #region Fields /// <summary> /// 每個線程,一個新的DataContext實例 /// </summary> [ThreadStatic] static readonly DataContext current = new DataClasses1DataContext(); #endregion #region Contructors #endregion #region Properties public static DataContext Current { get { return current; } } #endregion #region Methods #endregion #region Events #endregion }
上面代碼是一個生成LINQ上下文的工廠,你可以為每個LINQTOSQL類新建個基類,用來得到這個上下文,而具體操作類再去繼承這個基類,這在微軟的架構中,
會很常見,如System.Web.MVC.ControllerBase,它是Controller的基類。
/// <summary> /// DataClasses1DataContext數據庫基類 /// </summary> public abstract class DbBase { #region Fields #endregion #region Contructors #endregion #region Properties public DataClasses1DataContext Db = DbFactory.Current as DataClasses1DataContext; #endregion #region Methods #endregion #region Events #endregion }
而具體表的CURD操作,你可以單獨建立類文件,來做這件事
public class WebManageUsers_Ext : WebManageUsers { } public class UserDAL : DbBase { #region Fields #endregion #region Contructors #endregion #region Properties #endregion #region Methods public IQueryable<WebManageUsers> GetModel() { var linq = from data1 in base.Db.WebManageUsers join data2 in new DeptDAL().GetModel() on data1.DepartmentID equals data2.DepartmentID select new WebManageUsers_Ext { RealName = data1.RealName, WebDepartments = data2, }; return linq; } #endregion #region Events #endregion }
OK,如果將上面代碼輸出后,它的結果是正確的
事實上,上面我使用的復雜查詢,對於這種查詢,如果你的數據上下文不是static類型,它會出現異常的,一般異常為”為不能處理不同數據上下文的引用”,當然,這個提示是正常的,因為如果你的上下文為實例對象,那么,對於每個類來說,它都是不同的,都會被new一次!
當出現上面問題后,我們往往解決方法是使用static類型的上下文,而static類型本身在LINQTOSQL上就是有問題的,在進行數據更新操作時,所有線程,所有操作的LINQ緩存都是一個,在submitChange時,會出現提求混亂的情況,錯誤是不可預知的。所以,你不得不把所有的表關系查詢都寫在DAL層,將每個業務的復雜查詢方法都重寫一次,這樣才能解決“不能數據上下文”的問題,太可怕了,呵呵。
當然,你如果提前做了表關聯,使用LINQ的“立即加載”也是一個不錯的方式,它可以為你節省不少代碼,但它產生的SQL語句,其內查詢則是select * from table的格式,即返回了很多無用的列。
綜上所述:使用線程唯一的靜態數據上下文才是最好的解決方案!