線程共享的DbContext與私有的DbContext
在使用Linq to Sql做為底層ORM時,它為我們提供的數(shù)據(jù)上下文為DataContext對象,實現(xiàn)上我們通過拖動生成的DBML文件,它們都是繼承自 System.Data.Linq.DataContext類型的,所以DataContext就是LINQ數(shù)據(jù)對象的基類,有時,我們可以通過這種類的多態(tài)性來動態(tài)創(chuàng)建DB的實例。
在每個DataContext類中,它有幾個實例的構(gòu)造方法,用來讓你創(chuàng)建DataContext的實例,如下:
- /// <summary>
- /// 使用默認(rèn)的連接串創(chuàng)建實現(xiàn)(每拖一次數(shù)據(jù)庫,就會產(chǎn)生一個連接串)
- /// </summary>
- public DataClasses1DataContext() :
- base(global::test.Properties.Settings.Default.EEE114ConnectionString, mappingSource)
- {
- OnCreated();
- }
- /// <summary>
- /// 使用指定的連接串,可能配置在config文件里
- /// </summary>
- /// <param name="connection"></param>
- public DataClasses1DataContext(string connection) :
- base(connection, mappingSource)
- {
- OnCreated();
- }
- /// <summary>
- /// 使用使用了IDbConnection接口的對象創(chuàng)建實例
- /// </summary>
- /// <param name="connection"></param>
- public DataClasses1DataContext(System.Data.IDbConnection connection) :
- base(connection, mappingSource)
- {
- OnCreated();
- }
- /// <summary>
- /// 使用連接串和數(shù)據(jù)庫的映射文件來建立實例,mappingSource可能是一個XML文件
- /// </summary>
- /// <param name="connection"></param>
- /// <param name="mappingSource"></param>
- public DataClasses1DataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
- base(connection, mappingSource)
- {
- OnCreated();
- }
而我們在實現(xiàn)項目開發(fā)中,可能用第二種比較多,即
- DataClasses1DataContext db=new LINQ.DataClasses1DataContext(System.Configuration.ConfigurationManager.ConnectionStrings["XXB"].ToString())
這樣,在開發(fā)環(huán)境與生成環(huán)境只要配置一個CONFIG文件即可。靈活。
而今天的主題是線程共享的DbContext與私有的DbContext,所以開始書歸正轉(zhuǎn)了,對于ado.net架構(gòu)中,我們往往使用一個static全局對象來完成數(shù)據(jù)訪問工作,而在linq to sql中,如果你建立一個static對象,它會出現(xiàn)很多問題,這在實現(xiàn)開發(fā)過程中才可以體會到,所以,今天要說的不是static對象。
一 線程共享的DbContext,說清楚一點就是在一個線程內(nèi),你的DataContext對象是共享的,是一個對象,不是new出很多個datacontext對象來,這事實上是一種單例模式的體現(xiàn),這沒有問題,它解決了static對象所產(chǎn)生的問題,而又滿足了多表關(guān)聯(lián)查詢時出現(xiàn)(不能實現(xiàn)不同數(shù)據(jù)上下文件的引用,linq to sql和Ef都是這樣的)的問題。
代碼:
datacontext生成工廠:
- /// <summary>
- /// 數(shù)據(jù)庫建立工廠
- /// Created By : 張占嶺
- /// Created Date:2011-10-14
- /// Modify By:
- /// Modify Date:
- /// Modify Reason:
- /// </summary>
- internal sealed class DbFactory
- {
- #region Fields
- static System.Timers.Timer sysTimer = new System.Timers.Timer(10000);
- volatile static Dictionary<Thread, DbContext[]> divDataContext = new Dictionary<Thread, DbContext[]>();
- #endregion
- #region Constructors
- /// <summary>
- /// 類構(gòu)造方法
- /// </summary>
- static DbFactory()
- {
- sysTimer.AutoReset = true;
- sysTimer.Enabled = true;
- sysTimer.Elapsed += new System.Timers.ElapsedEventHandler(sysTimer_Elapsed);
- sysTimer.Start();
- }
- #endregion
- #region Static Methods
- /// <summary>
- /// 訂閱Elapsed事件的方法
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- static void sysTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
- {
- List<Thread> list = divDataContext.Keys.Where(item => item.ThreadState == ThreadState.Stopped).ToList();
- for (int index = 0; index < list.Count; index++)
- {
- for (int refer = 0; refer < divDataContext[list[index]].Length; refer++)
- if (divDataContext[list[index]][refer] != null)
- {
- divDataContext[list[index]][refer].Dispose();
- divDataContext[list[index]][refer] = null;
- }
- divDataContext.Remove(list[index]);
- list[index] = null;
- }
- }
- /// <summary>
- /// 通過工廠的制造模式獲取相應(yīng)的LINQ數(shù)據(jù)庫連接對象
- /// </summary>
- /// <param name="dbName">數(shù)據(jù)庫名稱(需要與真實數(shù)據(jù)庫名稱保持一致)</param>
- /// <returns>LINQ數(shù)據(jù)庫連接對象</returns>
- public static DbContext Intance(string dbName)
- {
- return Intance(dbName, Thread.CurrentThread, 1, 0);
- }
- /// <summary>
- /// 通過工廠的制造模式獲取相應(yīng)的LINQ數(shù)據(jù)庫連接對象
- /// </summary>
- /// <param name="dbName"></param>
- /// <param name="dbCount"></param>
- /// <param name="dbIndex"></param>
- /// <returns></returns>
- public static DbContext Intance(string dbName, int dbCount, int dbIndex)
- {
- return Intance(dbName, Thread.CurrentThread, dbCount, dbIndex);
- }
- /// <summary>
- /// 通過工廠的制造模式獲取相應(yīng)的LINQ數(shù)據(jù)庫連接對象
- /// </summary>
- /// <param name="dbName">數(shù)據(jù)庫名稱(需要與真實數(shù)據(jù)庫名稱保持一致)</param>
- /// <param name="thread">當(dāng)前線程引用的對象</param>
- /// <param name="dbCount">linq to sql數(shù)據(jù)庫數(shù)量</param>
- /// <param name="dbIndex">當(dāng)前索引</param>
- /// <returns>LINQ對象上下文</returns>
- public static DbContext Intance(string dbName, Thread thread, int dbCount, int dbIndex)
- {
- if (!divDataContext.Keys.Contains(thread))
- {
- divDataContext.Add(thread, new DbContext[dbCount]);
- }
- if (divDataContext[thread][dbIndex] == null)
- {
- divDataContext[thread][dbIndex] = new DbContext(dbName);
- }
- return divDataContext[thread][dbIndex];
- }
- /// <summary>
- /// 通過工廠的制造模式獲取相應(yīng)的LINQ數(shù)據(jù)庫連接對象
- /// </summary>
- /// <param name="dbName"></param>
- /// <param name="thread"></param>
- /// <returns></returns>
- public static DbContext Intance(string dbName, Thread thread)
- {
- return Intance(dbName, thread, 1, 0);
- }
- #endregion
- }
具體領(lǐng)域數(shù)據(jù)對象創(chuàng)建時代碼如下:
- /// <summary>
- /// XXB數(shù)據(jù)庫基類
- /// </summary>
- public class XXB_DataBase : DataBase
- {
- private readonly static string _conn;
- static XXB_DataBase()
- {
- if (ConfigurationManager.ConnectionStrings["XXB"] == null)
- throw new Exception("請設(shè)置XXB配置字符");
- else
- _conn = ConfigurationManager.ConnectionStrings["XXB"].ToString();
- }
- public XXB_DataBase()
- : base(DbFactory.Intance(_conn, 2, 1))
- { }
- }
二 私有的DbContext,它要求你為每個表都建立一個repository對象,用戶對表進(jìn)行CURD操作,而它們都繼承一個database,在 database里有唯一創(chuàng)建datacontext的入口,這樣在做多表關(guān)聯(lián)時,使用的是同一個datacontext對象,所以不會出現(xiàn)“不能實現(xiàn)不同數(shù)據(jù)上下文件的引用”這種問題,但這樣方式感覺很不爽,因為你必須把所有多表關(guān)聯(lián)的業(yè)務(wù)邏輯,寫在DAL層,這是很郁悶的,因為一般我們會把它放在BLL層(更有利于業(yè)務(wù)的組合與重用)。
代碼:
具體領(lǐng)域數(shù)據(jù)基類:
- /// <summary>
- /// XXB數(shù)據(jù)基類
- /// </summary>
- public abstract class XXBBase : DataBase
- {
- public XXBBase()
- : base(new LINQ.DataClasses1DataContext(System.Configuration.ConfigurationManager.ConnectionStrings["XXB"].ToString()))
- { }
- }
統(tǒng)一數(shù)據(jù)基類:
- /// <summary>
- /// 標(biāo)準(zhǔn)數(shù)據(jù)操作基類
- /// </summary>
- public abstract class DataBase : IRepository
- {
- /// <summary>
- /// 數(shù)據(jù)訪問對象(只對子類可見)
- /// </summary>
- protected DataContext DB;
- #region Constructors
- public DataBase(DataContext db)
- : this(() => { return db; })
- { }
- public DataBase(Func<DataContext> func)
- {
- this.DB = func();
- }
- #endregion
- #region DBContext SubmitChanges
- /// <summary>
- /// XXB默認(rèn)提交【重寫時候可能需要寫入自定義的類似約束的邏輯】
- /// </summary>
- protected virtual void SubmitChanges()
- {
- ChangeSet cSet = DB.GetChangeSet();
- if (cSet.Inserts.Count > 0
- || cSet.Updates.Count > 0
- || cSet.Deletes.Count > 0)
- {
- try
- {
- DB.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
- }
- catch (System.Data.Linq.ChangeConflictException)
- {
- foreach (System.Data.Linq.ObjectChangeConflict occ in DB.ChangeConflicts)
- {
- occ.Resolve(System.Data.Linq.RefreshMode.OverwriteCurrentValues);
- occ.Resolve(System.Data.Linq.RefreshMode.KeepCurrentValues);
- occ.Resolve(System.Data.Linq.RefreshMode.KeepChanges);
- }
- DB.SubmitChanges();
- }
- }
- }
- #endregion
- #region IRepository 成員
- public virtual void Update<TEntity>(TEntity entity) where TEntity : class
- {
- this.SubmitChanges();
- }
- public virtual void Update<TEntity>(IEnumerable<TEntity> list) where TEntity : class
- {
- list.ToList().ForEach(entity =>
- {
- this.Update<TEntity>(entity);
- });
- }
- public virtual void Insert<TEntity>(TEntity entity) where TEntity : class
- {
- DB.GetTable<TEntity>().InsertOnSubmit(entity);
- this.SubmitChanges();
- }
- public virtual void Insert<TEntity>(IEnumerable<TEntity> list) where TEntity : class
- {
- DB.GetTable<TEntity>().InsertAllOnSubmit<TEntity>(list);
- this.SubmitChanges();
- }
- public virtual TEntity InsertGetIDENTITY<TEntity>(TEntity entity) where TEntity : class
- {
- this.Insert<TEntity>(entity);
- return GetModel<TEntity>(i => i == entity).FirstOrDefault();
- }
- public virtual void Delete<TEntity>(TEntity entity) where TEntity : class
- {
- DB.GetTable<TEntity>().DeleteOnSubmit(entity);
- this.SubmitChanges();
- }
- public virtual void Delete<TEntity>(IEnumerable<TEntity> list) where TEntity : class
- {
- DB.GetTable<TEntity>().DeleteAllOnSubmit<TEntity>(list);
- this.SubmitChanges();
- }
- public virtual IQueryable<TEntity> GetModel<TEntity>() where TEntity : class
- {
- return this.DB.GetTable<TEntity>();
- }
- public virtual IQueryable<TEntity> GetModel<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> predicate) where TEntity : class
- {
- return GetModel<TEntity>().Where(predicate);
- }
- public virtual TEntity Find<TEntity>(params object[] keyValues) where TEntity : class
- {
- var mapping = DB.Mapping.GetTable(typeof(TEntity));
- var keys = mapping.RowType.IdentityMembers.Select((m, i) => m.Name + " = @" + i).ToArray();
- TEntity entityTEntity = DB.GetTable<TEntity>().Where(String.Join(" && ", keys), keyValues).FirstOrDefault();
- if (entityTEntity != null)
- DB.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, entityTEntity);
- return entityTEntity;
- }
- #endregion
- }
而用戶模塊User_InfoRepository在做多表關(guān)聯(lián)時,是這樣完成的:
- public class User_InfoRepository : XXBBase
- {
- /// <summary>
- /// 需要把Join的表關(guān)系寫在這里
- /// </summary>
- /// <returns></returns>
- public IQueryable<User_Info> GetDetailModel()
- {
- var linq = from data1 in base.GetModel<User_Info>()
- join data2 in base.GetModel<User_Profile>() on data1.UserID equals data2.UserID
- select data1;
- return linq;
- }
- }
原文鏈接:http://www.cnblogs.com/lori/archive/2012/08/23/2653426.html