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的格式,即傳回了很多無用的列。