最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对

来源:动视网 责编:小采 时间:2020-11-09 08:07:27
文档

LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对

LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对:回到目录 这个文章写的有点滞后了,呵呵,因为总想把之前不确定的东西确定了之后,再写这篇,之前的LINQ-to-SQL那点事,请点这里。 LINQ-to-SQL中的数据缓存与应对 Linq-to-SQL它是微软自己推出的一个轻量级的ORM框架,它很好地完成了与SQLSERVER数
推荐度:
导读LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对:回到目录 这个文章写的有点滞后了,呵呵,因为总想把之前不确定的东西确定了之后,再写这篇,之前的LINQ-to-SQL那点事,请点这里。 LINQ-to-SQL中的数据缓存与应对 Linq-to-SQL它是微软自己推出的一个轻量级的ORM框架,它很好地完成了与SQLSERVER数


回到目录 这个文章写的有点滞后了,呵呵,因为总想把之前不确定的东西确定了之后,再写这篇,之前的LINQ-to-SQL那点事,请点这里。 LINQ-to-SQL中的数据缓存与应对 Linq-to-SQL它是微软自己推出的一个轻量级的ORM框架,它很好地完成了与SQLSERVER数据库的映

回到目录

这个文章写的有点滞后了,呵呵,因为总想把之前不确定的东西确定了之后,再写这篇,之前的LINQ-to-SQL那点事,请点这里。

LINQ-to-SQL中的数据缓存与应对

Linq-to-SQL它是微软自己推出的一个轻量级的ORM框架,它很好地完成了与SQLSERVER数据库的映射(它目前只支持SQLSERVER,也不会有以后的,因为微软不对它进行更新了),在使用它时,微软提出了“数据上下文”的概念,这个上下文(context)类似于HttpContext,RequestContext,是指对某种事物的完整的抽象,把对这种事物的操作都集成在上下文中。

Linq-to-SQL的上下文被称为DataContext,它进一步的封装了SQL语句,亮点在于它的查询上,支持延时查询,再配合linq的语法,使得开发人员在写代码时很优雅,代码表现力更强。

DataContext在性能方面提出了缓存的概念,它可以装查询出来的数据缓存到上下文中(这有时会产生并发问题),对于Insert,Update,Delete这类执行类操作也提供了缓存语句,每当SubmitChange方法被触发时,这时缓存的语句被一次性的提交到SQLSERVER,之后将当前上下文的缓存语句清空。

一个线程单例的数据上下文的提出:

当你希望把延时的数据返回到表示层时,DataContext如果被dispose之后,这种操作是不被允许的,这是正确的,因为你的数据上下文可能在表示层方法执行前已经被dispose了,一般这种代码会被这样书写:

 public IQueryable GetOrder_Info(Expression> predicate)
 {
 using (var datacontext = new LinqDataContext())
 {
 return datacontext.Where(predicate);
 }
 }

这段代码在执行上当然是有问题的,使用了using关键字后,在方法return这数据上下文DataContext将会被dispose,这是正常的,而由于linq语句返回的是IQueryable延时结果集,它将不会立即执行,只有真正返回数据时才会通过DataContext与SQLSERVER进行交互,而在上层方法中,由于DataContext这时已经被dispose了,所以,语句最终会报异常。

面对这种问题,我们知道了它的原因,所以接下来就寻找一种解决方法,即不叫DataContext立即dispose的方法,你可能会很容易的想到“把using去掉不就可以了”,事实上,如果你对linq to sql了解的话,这种做法是不可取的,因为这样,你在业务逻辑层无法实现“复杂查询,linq join”(一般地,我们为每个DAL层的表对象写几个方法,可能是根据条件去查询数据的方法),为什么呢?因为,对于一个linq查询语句来说,你的数据上下文必须是同一个才行,如果用户业务使用一个上下文,而订单业务使用另一个上下文,那么,这两个业务进行组成查询时,就会出现不同数据上下文的问题。

代码可能是这样:

 var linq =from user in userBLL().GetModel()
 join order in orderBLL().GetModel() on user.UserID equals order.UserID
 select new user_Ext
{ ... }

为数据上下文添加一个工厂,用来生成由UI线程产生的数据上下文,再把这些上下文放在一个由UI线程作为键的字典里,当UI线程中的数据上下文在进行SubmitChange出现异常进,我们再将当然上下文dispose,并从数据上下文字典中移除它。

数据上下文工厂及数据上下文基类代码如下:

 /// 
 /// 数据库建立工厂
 /// Created By : 张占岭
 /// Created Date:2011-10-14
 /// Modify By:
 /// Modify Date:
 /// Modify Reason:
 /// 
 internal static class DbFactory
 {
 #region Fields
 static readonly string strConn = System.Configuration.ConfigurationManager.ConnectionStrings["test"].ToString();
 static System.Timers.Timer sysTimer;
 volatile static Dictionary divDataContext;
 #endregion

 #region Constructors
 static DbFactory()
 {
 divDataContext = new Dictionary();
 sysTimer = new System.Timers.Timer(10000);
 sysTimer.AutoReset = true;
 sysTimer.Enabled = true;
 sysTimer.Elapsed += new System.Timers.ElapsedEventHandler(sysTimer_Elapsed);
 sysTimer.Start();
 }
 #endregion

 #region Private Methods
 /// 
 /// 清理DbContext上下文
 /// 
 /// 
 /// 
 static void sysTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
 {
 List list = divDataContext.Keys
 .Where(item => item.ThreadState == ThreadState.Stopped)
 .ToList();
 if (list != null && list.Count > 0)
 {
 foreach (var thread in list)
 {
 foreach (var context in divDataContext[thread])
 {
 if (context != null)
 context.Dispose();
 }
 }
 }
 }
 #endregion

 #region Public Methods
 /// 
 /// 通过工厂的制造模式获取相应的LINQ数据库连接对象
 /// 
 /// 数据库名称(需要与真实数据库名称保持一致)
 /// LINQ数据库连接对象
 public static DataContext Intance(string dbName)
 {
 return Intance(dbName, Thread.CurrentThread);
 }

 /// 
 /// 通过工厂的制造模式获取相应的LINQ数据库连接对象
 /// 
 /// 数据库名称(需要与真实数据库名称保持一致)
 /// 当前线程引用的对象
 /// LINQ数据库连接对象
 public static DataContext Intance(string dbName, Thread thread)
 {

 if (!divDataContext.Keys.Contains(thread))
 {
 divDataContext.Add(thread, new DataContext[3]);
 }

 if (dbName.Equals("test"))
 {
 if (divDataContext[thread][0] == null)
 {
 divDataContext[thread][0] = new DAL.dbDataContext(strConn);
 }
 return divDataContext[thread][0];
 }

return null;

 }

 /// 
 /// 手动清除数据上下文,根据线程
 /// 
 /// 
 public static void ClearContextByThread(Thread thread, DataContext db)
 {
 divDataContext.Remove(thread);//从线程字典中移除
 db.Dispose();//释放数据资源
 }
 #endregion

 }

下面是DataContext基类,已经对SubmitChanges(SaveChanges)方法进行了优化,手动dispose上下文。

/// 
 /// Repository基类
 /// 所有linqTosql上下文对象都继承它
 /// 
 public abstract class ContextBase
 {
 protected DataContext _db { get; private set; }
 protected IUnitOfWork UnitOfWork { get; private set; }
 public ContextBase(DataContext db)
 {
 _db = db;
 UnitOfWork = (IUnitOfWork)db;
 }
 public void SaveChanges()
 {
 ChangeSet cSet = _db.GetChangeSet();
 if ((cSet.Inserts.Count > 0
 || cSet.Updates.Count > 0
 || cSet.Deletes.Count > 0)
 && !UnitOfWork.IsNotSubmit)
 {
 try
 {
 UnitOfWork.SaveChanges();
 }
 catch (System.Data.Linq.ChangeConflictException)
 {
 foreach (System.Data.Linq.ObjectChangeConflict occ in _db.ChangeConflicts)
 {
 // 使用当前数据库中的值,覆盖Linq缓存中实体对象的值 
 occ.Resolve(System.Data.Linq.RefreshMode.OverwriteCurrentValues);
 // 使用Linq缓存中实体对象的值,覆盖当前数据库中的值 
 occ.Resolve(System.Data.Linq.RefreshMode.KeepCurrentValues);
 // 只更新实体对象中改变的字段的值,其他的保留不变 
 occ.Resolve(System.Data.Linq.RefreshMode.KeepChanges);
 }
 UnitOfWork.SaveChanges();
 }
 catch (Exception)//如果出现异常,就从数据字典中清除这个键值对
 {
 DbFactory.ClearContextByThread(System.Threading.Thread.CurrentThread, _db);
 }
 }
 }
 }

下面是一个领域的repository基类,代码如下:

 /// 
 /// Test数据库基类
 /// Created By : 张占岭
 /// Created Date:2011-10-14
 /// Modify By:
 /// Modify Date:
 /// Modify Reason:
 /// 
 public abstract class TestBase : ContextBase
 {
 #region Constructors
 public EEE114Base()
 : this(null)
 { }

 public EEE114Base(IUnitOfWork db)
 : base((DataContext)db ?? DbFactory.Intance("test", Thread.CurrentThread))
 { }
 #endregion

 #region Protected Properies
 /// 
 /// 可以使用的数据库连接对象
 /// [xxb]
 /// 
 protected dbDataContext db
 {
 get
 {
 return (dbDataContext)base._db;
 }
 }

 #endregion
 }
}

OK,这就是改善之后的linq to sql架构的核心代码,主要体现在生成数据上下文对象上,及如何去避免并发冲突的产生,而对于并发冲突我们会在另一篇文章中做详细的说明。敬请期待!

回到目录

文档

LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对

LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对:回到目录 这个文章写的有点滞后了,呵呵,因为总想把之前不确定的东西确定了之后,再写这篇,之前的LINQ-to-SQL那点事,请点这里。 LINQ-to-SQL中的数据缓存与应对 Linq-to-SQL它是微软自己推出的一个轻量级的ORM框架,它很好地完成了与SQLSERVER数
推荐度:
标签: 中的 数据 缓存
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top