LINQ-to-SQL那點事~線程(cheng)共享的DbContext與私有(you)的DbContext
在使用Linq to Sql做為(wei)底層ORM時,它(ta)(ta)為(wei)我(wo)(wo)們(men)提供(gong)的(de)數據上(shang)下文為(wei)DataContext對(dui)象,實(shi)(shi)現上(shang)我(wo)(wo)們(men)通(tong)過(guo)拖動(dong)生(sheng)成的(de)DBML文件,它(ta)(ta)們(men)都是(shi)繼承自(zi) System.Data.Linq.DataContext類型(xing)的(de),所以(yi)DataContext就是(shi)LINQ數據對(dui)象的(de)基類,有時,我(wo)(wo)們(men)可以(yi)通(tong)過(guo)這種類的(de)多態性來動(dong)態創建DB的(de)實(shi)(shi)例(li)。
在每個DataContext類(lei)中,它有(you)幾個實例的(de)構造方法,用來讓你創建DataContext的(de)實例,如(ru)下:
1 /// <summary> 2 /// 使用默認的連(lian)接串(chuan)創(chuang)建(jian)實現(xian)(每拖一(yi)次數據庫,就會產生(sheng)一(yi)個連(lian)接串(chuan)) 3 /// </summary> 4 public DataClasses1DataContext() : 5 base(global::test.Properties.Settings.Default.EEE114ConnectionString, mappingSource) 6 { 7 OnCreated(); 8 } 9 /// <summary> 10 /// 使用指定的連(lian)接(jie)串,可能配置在config文(wen)件里 11 /// </summary> 12 /// <param name="connection"></param> 13 public DataClasses1DataContext(string connection) : 14 base(connection, mappingSource) 15 { 16 OnCreated(); 17 } 18 /// <summary> 19 /// 使用使用了(le)IDbConnection接(jie)口的對象創建實例 20 /// </summary> 21 /// <param name="connection"></param> 22 public DataClasses1DataContext(System.Data.IDbConnection connection) : 23 base(connection, mappingSource) 24 { 25 OnCreated(); 26 } 27 /// <summary> 28 /// 使用連接串(chuan)和數(shu)據庫的(de)映射文件(jian)來建立實例,mappingSource可能是一(yi)個XML文件(jian) 29 /// </summary> 30 /// <param name="connection"></param> 31 /// <param name="mappingSource"></param> 32 public DataClasses1DataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) : 33 base(connection, mappingSource) 34 { 35 OnCreated(); 36 }
而我們在實現(xian)項目開發中,可(ke)能用第(di)二(er)種比(bi)較多(duo),即
1 DataClasses1DataContext db=new LINQ.DataClasses1DataContext(System.Configuration.ConfigurationManager.ConnectionStrings["XXB"].ToString())
這樣(yang),在開(kai)發(fa)環境與生(sheng)成環境只(zhi)要配置一個CONFIG文件即可(ke)。靈活。
而今天的主題是線(xian)程(cheng)共享的DbContext與(yu)私有(you)的DbContext,所(suo)以(yi)(yi)(yi)開始書歸正(zheng)轉了,對(dui)于ado.net架構(gou)中,我們往往使用一個static全局(ju)對(dui)象來完成數據訪(fang)問工作,而在(zai)linq to sql中,如果(guo)你建立一個static對(dui)象,它(ta)會(hui)出現很多問題,這(zhe)在(zai)實現開發過程(cheng)中才可以(yi)(yi)(yi)體會(hui)到,所(suo)以(yi)(yi)(yi),今天要說的不是static對(dui)象。
一(yi)(yi) 線程共享的(de)(de)(de)DbContext,說清楚一(yi)(yi)點就是(shi)(shi)(shi)在(zai)一(yi)(yi)個線程內(nei),你的(de)(de)(de)DataContext對(dui)(dui)象(xiang)是(shi)(shi)(shi)共享的(de)(de)(de),是(shi)(shi)(shi)一(yi)(yi)個對(dui)(dui)象(xiang),不是(shi)(shi)(shi)new出(chu)很多個datacontext對(dui)(dui)象(xiang)來,這事(shi)實上(shang)是(shi)(shi)(shi)一(yi)(yi)種單例(li)模式(shi)的(de)(de)(de)體現,這沒(mei)有(you)問題,它(ta)解決了static對(dui)(dui)象(xiang)所產生的(de)(de)(de)問題,而又滿足了多表關聯查詢時出(chu)現(不能實現不同數(shu)據(ju)上(shang)下文件的(de)(de)(de)引用,linq to sql和Ef都是(shi)(shi)(shi)這樣的(de)(de)(de))的(de)(de)(de)問題。
代碼:
datacontext生成工(gong)廠:
1 /// <summary> 2 /// 數據(ju)庫建立工廠 3 /// Created By : 張占嶺 4 /// Created Date:2011-10-14 5 /// Modify By: 6 /// Modify Date: 7 /// Modify Reason: 8 /// </summary> 9 internal sealed class DbFactory 10 { 11 #region Fields 12 static System.Timers.Timer sysTimer = new System.Timers.Timer(10000); 13 volatile static Dictionary<Thread, DataContext[]> divDataContext = new Dictionary<Thread, DataContext[]>(); 14 #endregion 15 16 #region Constructors 17 /// <summary> 18 /// 類構造(zao)方(fang)法 19 /// </summary> 20 static DbFactory() 21 { 22 sysTimer.AutoReset = true; 23 sysTimer.Enabled = true; 24 sysTimer.Elapsed += new System.Timers.ElapsedEventHandler(sysTimer_Elapsed); 25 sysTimer.Start(); 26 } 27 #endregion 28 29 #region Static Methods 30 31 /// <summary> 32 /// 訂閱Elapsed事件(jian)的方法 33 /// </summary> 34 /// <param name="sender"></param> 35 /// <param name="e"></param> 36 static void sysTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 37 { 38 List<Thread> list = divDataContext.Keys.Where(item => item.ThreadState == ThreadState.Stopped).ToList(); 39 for (int index = 0; index < list.Count; index++) 40 { 41 for (int refer = 0; refer < divDataContext[list[index]].Length; refer++) 42 if (divDataContext[list[index]][refer] != null) 43 { 44 divDataContext[list[index]][refer].Dispose(); 45 divDataContext[list[index]][refer] = null; 46 } 47 divDataContext.Remove(list[index]); 48 list[index] = null; 49 } 50 } 51 /// <summary> 52 /// 通過工廠的制造模(mo)式獲取相應(ying)的LINQ數(shu)據(ju)庫連接(jie)對象(xiang) 53 /// </summary> 54 /// <param name="dbName">數(shu)(shu)據(ju)庫名稱(cheng)(需要與真實數(shu)(shu)據(ju)庫名稱(cheng)保(bao)持一致)</param> 55 /// <returns>LINQ數據庫連接對象(xiang)</returns> 56 public static DataContextIntance(string dbName) 57 { 58 return Intance(dbName, Thread.CurrentThread, 1, 0); 59 } 60 61 /// <summary> 62 /// 通過工廠的制造(zao)模式獲(huo)取相應的LINQ數據庫連接對(dui)象(xiang) 63 /// </summary> 64 /// <param name="dbName"></param> 65 /// <param name="dbCount"></param> 66 /// <param name="dbIndex"></param> 67 /// <returns></returns> 68 public static DataContextIntance(string dbName, int dbCount, int dbIndex) 69 { 70 return Intance(dbName, Thread.CurrentThread, dbCount, dbIndex); 71 } 72 73 /// <summary> 74 /// 通過工廠的(de)制造模式獲取相應(ying)的(de)LINQ數(shu)據庫連接對象 75 /// </summary> 76 /// <param name="dbName">數據庫名稱(cheng)(需(xu)要(yao)與(yu)真實數據庫名稱(cheng)保(bao)持(chi)一致)</param> 77 /// <param name="thread">當前(qian)線程引(yin)用的對象(xiang)</param> 78 /// <param name="dbCount">linq to sql數(shu)據(ju)庫數(shu)量</param> 79 /// <param name="dbIndex">當前索引</param> 80 /// <returns>LINQ對象(xiang)上下文</returns> 81 public static DataContextIntance(string dbName, Thread thread, int dbCount, int dbIndex) 82 { 83 if (!divDataContext.Keys.Contains(thread)) 84 { 85 divDataContext.Add(thread, new DbContext[dbCount]); 86 } 87 if (divDataContext[thread][dbIndex] == null) 88 { 89 divDataContext[thread][dbIndex] = new DbContext(dbName); 90 } 91 return divDataContext[thread][dbIndex]; 92 } 93 94 /// <summary> 95 /// 通過工廠的(de)(de)制造模式(shi)獲取相應的(de)(de)LINQ數據庫連接對(dui)象 96 /// </summary> 97 /// <param name="dbName"></param> 98 /// <param name="thread"></param> 99 /// <returns></returns> 100 public static DataContextIntance(string dbName, Thread thread) 101 { 102 return Intance(dbName, thread, 1, 0); 103 } 104 #endregion 105 106 }
具體(ti)領域(yu)數據(ju)對象創建(jian)時代(dai)碼如下:
1 /// <summary> 2 /// XXB數據庫(ku)基類 3 /// </summary> 4 public class XXB_DataBase : DataBase 5 { 6 private readonly static string _conn; 7 static XXB_DataBase() 8 { 9 if (ConfigurationManager.ConnectionStrings["XXB"] == null) 10 throw new Exception("請(qing)設置XXB配置字(zi)符"); 11 else 12 _conn = ConfigurationManager.ConnectionStrings["XXB"].ToString(); 13 } 14 public XXB_DataBase() 15 : base(DbFactory.Intance(_conn, 2, 1)) 16 { } 17 18 }
二 私有的(de)DbContext,它要求(qiu)你(ni)(ni)為每個表都(dou)建立(li)一(yi)個repository對(dui)象,用(yong)戶(hu)對(dui)表進行(xing)CURD操作,而它們(men)都(dou)繼承一(yi)個database,在 database里有唯一(yi)創建datacontext的(de)入口,這(zhe)樣(yang)在做多表關聯時(shi),使(shi)用(yong)的(de)是(shi)同(tong)一(yi)個datacontext對(dui)象,所以不會出(chu)現(xian)“不能實現(xian)不同(tong)數據上下文件的(de)引用(yong)”這(zhe)種問題,但這(zhe)樣(yang)方式感覺很(hen)不爽,因為你(ni)(ni)必須把(ba)所有多表關聯的(de)業務邏輯,寫在DAL層,這(zhe)是(shi)很(hen)郁悶的(de),因為一(yi)般我們(men)會把(ba)它放在BLL層(更有利于業務的(de)組(zu)合(he)與重用(yong))。
代碼:
具體領域數據基類:
1 /// <summary> 2 /// XXB數據基類(lei) 3 /// </summary> 4 public abstract class XXBBase : DataBase 5 { 6 public XXBBase() 7 : base(new LINQ.DataClasses1DataContext(System.Configuration.ConfigurationManager.ConnectionStrings["XXB"].ToString())) 8 { } 9 }
統一數據基類:
1 /// <summary> 2 /// 標準數據(ju)操作基類 3 /// </summary> 4 public abstract class DataBase : IRepository 5 { 6 /// <summary> 7 /// 數據訪問對(dui)象(只(zhi)對(dui)子類(lei)可見) 8 /// </summary> 9 protected DataContext DB; 10 11 #region Constructors 12 public DataBase(DataContext db) 13 : this(() => { return db; }) 14 { } 15 public DataBase(Func<DataContext> func) 16 { 17 this.DB = func(); 18 } 19 #endregion 20 21 #region DBContext SubmitChanges 22 /// <summary> 23 /// XXB默認提交【重(zhong)寫(xie)(xie)時候可能需要(yao)寫(xie)(xie)入自定義的(de)(de)類(lei)似約束(shu)的(de)(de)邏輯(ji)】 24 /// </summary> 25 protected virtual void SubmitChanges() 26 { 27 ChangeSet cSet = DB.GetChangeSet(); 28 if (cSet.Inserts.Count > 0 29 || cSet.Updates.Count > 0 30 || cSet.Deletes.Count > 0) 31 { 32 try 33 { 34 DB.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict); 35 } 36 catch (System.Data.Linq.ChangeConflictException) 37 { 38 foreach (System.Data.Linq.ObjectChangeConflict occ in DB.ChangeConflicts) 39 { 40 occ.Resolve(System.Data.Linq.RefreshMode.OverwriteCurrentValues); 41 occ.Resolve(System.Data.Linq.RefreshMode.KeepCurrentValues); 42 occ.Resolve(System.Data.Linq.RefreshMode.KeepChanges); 43 } 44 DB.SubmitChanges(); 45 } 46 } 47 } 48 49 #endregion 50 51 #region IRepository 成員 52 53 public virtual void Update<TEntity>(TEntity entity) where TEntity : class 54 { 55 this.SubmitChanges(); 56 57 } 58 59 public virtual void Update<TEntity>(IEnumerable<TEntity> list) where TEntity : class 60 { 61 list.ToList().ForEach(entity => 62 { 63 this.Update<TEntity>(entity); 64 }); 65 } 66 67 public virtual void Insert<TEntity>(TEntity entity) where TEntity : class 68 { 69 DB.GetTable<TEntity>().InsertOnSubmit(entity); 70 this.SubmitChanges(); 71 } 72 73 public virtual void Insert<TEntity>(IEnumerable<TEntity> list) where TEntity : class 74 { 75 DB.GetTable<TEntity>().InsertAllOnSubmit<TEntity>(list); 76 this.SubmitChanges(); 77 } 78 79 public virtual TEntity InsertGetIDENTITY<TEntity>(TEntity entity) where TEntity : class 80 { 81 this.Insert<TEntity>(entity); 82 return GetModel<TEntity>(i => i == entity).FirstOrDefault(); 83 } 84 85 public virtual void Delete<TEntity>(TEntity entity) where TEntity : class 86 { 87 DB.GetTable<TEntity>().DeleteOnSubmit(entity); 88 this.SubmitChanges(); 89 } 90 91 public virtual void Delete<TEntity>(IEnumerable<TEntity> list) where TEntity : class 92 { 93 DB.GetTable<TEntity>().DeleteAllOnSubmit<TEntity>(list); 94 this.SubmitChanges(); 95 } 96 97 public virtual IQueryable<TEntity> GetModel<TEntity>() where TEntity : class 98 { 99 return this.DB.GetTable<TEntity>(); 100 } 101 102 public virtual IQueryable<TEntity> GetModel<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> predicate) where TEntity : class 103 { 104 return GetModel<TEntity>().Where(predicate); 105 } 106 107 public virtual TEntity Find<TEntity>(params object[] keyValues) where TEntity : class 108 { 109 var mapping = DB.Mapping.GetTable(typeof(TEntity)); 110 var keys = mapping.RowType.IdentityMembers.Select((m, i) => m.Name + " = @" + i).ToArray(); 111 TEntity entityTEntity = DB.GetTable<TEntity>().Where(String.Join(" && ", keys), keyValues).FirstOrDefault(); 112 if (entityTEntity != null) 113 DB.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, entityTEntity); 114 return entityTEntity; 115 } 116 117 #endregion 118 }
而用(yong)戶模塊User_InfoRepository在做多表(biao)關聯時,是(shi)這(zhe)樣完成的:
1 public class User_InfoRepository : XXBBase 2 { 3 /// <summary> 4 /// 需要把Join的表關系寫在(zai)這里 5 /// </summary> 6 /// <returns></returns> 7 public IQueryable<User_Info> GetDetailModel() 8 { 9 var linq = from data1 in base.GetModel<User_Info>() 10 join data2 in base.GetModel<User_Profile>() on data1.UserID equals data2.UserID 11 select data1; 12 return linq; 13 } 14 }
回到目錄