zoukankan      html  css  js  c++  java
  • LINQtoSQL那点事~线程共享的DbContext与私有的DbContext

    回到目录    

      在使用Linq to Sql做为底层ORM时,它为我们提供的数据上下文为DataContext对象,实现上我们通过拖动生成的DBML文件,它们都是继承自 System.Data.Linq.DataContext类型的,所以DataContext就是LINQ数据对象的基类,有时,我们可以通过这种类的多态性来动态创建DB的实例。

         在每个DataContext类中,它有几个实例的构造方法,用来让你创建DataContext的实例,如下:

     1     /// <summary>
     2         /// 使用默认的连接串创建实现(每拖一次数据库,就会产生一个连接串)
     3         /// </summary>
     4         public DataClasses1DataContext() : 
     5                 base(global::test.Properties.Settings.Default.EEE114ConnectionString, mappingSource)
     6         {
     7             OnCreated();
     8         }
     9         /// <summary>
    10         /// 使用指定的连接串,可能配置在config文件里
    11         /// </summary>
    12         /// <param name="connection"></param>
    13         public DataClasses1DataContext(string connection) : 
    14                 base(connection, mappingSource)
    15         {
    16             OnCreated();
    17         }
    18         /// <summary>
    19         /// 使用使用了IDbConnection接口的对象创建实例
    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         /// 使用连接串和数据库的映射文件来建立实例,mappingSource可能是一个XML文件
    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         }

    而我们在实现项目开发中,可能用第二种比较多,即

    1 DataClasses1DataContext db=new LINQ.DataClasses1DataContext(System.Configuration.ConfigurationManager.ConnectionStrings["XXB"].ToString())

    这样,在开发环境与生成环境只要配置一个CONFIG文件即可。灵活。

    而今天的主题是线程共享的DbContext与私有的DbContext,所以开始书归正转了,对于ado.net架构中,我们往往使用一个static全局对象来完成数据访问工作,而在linq to sql中,如果你建立一个static对象,它会出现很多问题,这在实现开发过程中才可以体会到,所以,今天要说的不是static对象。

    一 线程共享的DbContext,说清楚一点就是在一个线程内,你的DataContext对象是共享的,是一个对象,不是new出很多个datacontext对象来,这事实上是一种单例模式的体现,这没有问题,它解决了static对象所产生的问题,而又满足了多表关联查询时出现(不能实现不同数据上下文件的引用,linq to sql和Ef都是这样的)的问题。

    代码:

    datacontext生成工厂:

      1     /// <summary>
      2     /// 数据库建立工厂
      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         /// 类构造方法
     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事件的方法
     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         /// 通过工厂的制造模式获取相应的LINQ数据库连接对象
     53         /// </summary>
     54         /// <param name="dbName">数据库名称(需要与真实数据库名称保持一致)</param>
     55         /// <returns>LINQ数据库连接对象</returns>
     56         public static DataContextIntance(string dbName)
     57         {
     58             return Intance(dbName, Thread.CurrentThread, 1, 0);
     59         }
     60 
     61         /// <summary>
     62         /// 通过工厂的制造模式获取相应的LINQ数据库连接对象
     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         /// 通过工厂的制造模式获取相应的LINQ数据库连接对象
     75         /// </summary>
     76         /// <param name="dbName">数据库名称(需要与真实数据库名称保持一致)</param>
     77         /// <param name="thread">当前线程引用的对象</param>
     78         /// <param name="dbCount">linq to sql数据库数量</param>
     79         /// <param name="dbIndex">当前索引</param>
     80         /// <returns>LINQ对象上下文</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         /// 通过工厂的制造模式获取相应的LINQ数据库连接对象
     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     }

    具体领域数据对象创建时代码如下:

     1 /// <summary>
     2     /// XXB数据库基类
     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("请设置XXB配置字符");
    11             else
    12                 _conn = ConfigurationManager.ConnectionStrings["XXB"].ToString();
    13         }
    14         public XXB_DataBase()
    15             : base(DbFactory.Intance(_conn, 2, 1))
    16         { }
    17 
    18     }

    二 私有的DbContext,它要求你为每个表都建立一个repository对象,用户对表进行CURD操作,而它们都继承一个database,在 database里有唯一创建datacontext的入口,这样在做多表关联时,使用的是同一个datacontext对象,所以不会出现“不能实现不同数据上下文件的引用”这种问题,但这样方式感觉很不爽,因为你必须把所有多表关联的业务逻辑,写在DAL层,这是很郁闷的,因为一般我们会把它放在BLL层(更有利于业务的组合与重用)。

    代码:

    具体领域数据基类:

    1  /// <summary>
    2     /// XXB数据基类
    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     /// 标准数据操作基类
      3     /// </summary>
      4     public abstract class DataBase : IRepository
      5     {
      6         /// <summary>
      7         /// 数据访问对象(只对子类可见)
      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默认提交【重写时候可能需要写入自定义的类似约束的逻辑】
     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     }

    而用户模块User_InfoRepository在做多表关联时,是这样完成的:

     1 public class User_InfoRepository : XXBBase
     2     {
     3         /// <summary>
     4         /// 需要把Join的表关系写在这里
     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     }

    回到目录

  • 相关阅读:
    php环境搭建工具包推荐
    Android视频直播解决方案(rstp、udp)
    软件版本号命名
    附加数据库失败,无法升级数据库,因为它是只读的
    Web Api如何传递POST请求
    找回Reshaprer的Alt+Enter快捷键的方法
    asp.net 实现在线打印功能,jQuery打印插件PrintArea实现自动分页
    asp.net 回发或回调参数无效的各种情况分析及解决办法
    MQTT, XMPP, WebSockets还是AMQP?泛谈实时通信协议选型 good
    echarts 专题
  • 原文地址:https://www.cnblogs.com/lori/p/2653426.html
Copyright © 2011-2022 走看看