LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对
这个文章写的有点滞后了,呵呵,因为总想把之前不确定的东西确定了之后,再写这篇,之前的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<Order_Info> GetOrder_Info(Expression<Func<Order_Info, bool>> 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,并从数据上下文字典中移除它。
数据上下文工厂及数据上下文基类代码如下:
- /// <summary>
- /// 数据库建立工厂
- /// Created By : 张占岭
- /// Created Date:2011-10-14
- /// Modify By:
- /// Modify Date:
- /// Modify Reason:
- /// </summary>
- internal static class DbFactory
- {
- #region Fields
- static readonly string strConn = System.Configuration.ConfigurationManager.ConnectionStrings["test"].ToString();
- static System.Timers.Timer sysTimer;
- volatile static Dictionary<Thread, DataContext[]> divDataContext;
- #endregion
- #region Constructors
- static DbFactory()
- {
- divDataContext = new Dictionary<Thread, DataContext[]>();
- sysTimer = new System.Timers.Timer();
- sysTimer.AutoReset = true;
- sysTimer.Enabled = true;
- sysTimer.Elapsed += new System.Timers.ElapsedEventHandler(sysTimer_Elapsed);
- sysTimer.Start();
- }
- #endregion
- #region Private Methods
- /// <summary>
- /// 清理DbContext上下文
- /// </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();
- if (list != null && list.Count > )
- {
- foreach (var thread in list)
- {
- foreach (var context in divDataContext[thread])
- {
- if (context != null)
- context.Dispose();
- }
- }
- }
- }
- #endregion
- #region Public Methods
- /// <summary>
- /// 通过工厂的制造模式获取相应的LINQ数据库连接对象
- /// </summary>
- /// <param name="dbName">数据库名称(需要与真实数据库名称保持一致)</param>
- /// <returns>LINQ数据库连接对象</returns>
- public static DataContext Intance(string dbName)
- {
- return Intance(dbName, Thread.CurrentThread);
- }
- /// <summary>
- /// 通过工厂的制造模式获取相应的LINQ数据库连接对象
- /// </summary>
- /// <param name="dbName">数据库名称(需要与真实数据库名称保持一致)</param>
- /// <param name="thread">当前线程引用的对象</param>
- /// <returns>LINQ数据库连接对象</returns>
- public static DataContext Intance(string dbName, Thread thread)
- {
- if (!divDataContext.Keys.Contains(thread))
- {
- divDataContext.Add(thread, new DataContext[]);
- }
- if (dbName.Equals("test"))
- {
- if (divDataContext[thread][] == null)
- {
- divDataContext[thread][] = new DAL.dbDataContext(strConn);
- }
- return divDataContext[thread][];
- }
- return null;
- }
- /// <summary>
- /// 手动清除数据上下文,根据线程
- /// </summary>
- /// <param name="thread"></param>
- public static void ClearContextByThread(Thread thread, DataContext db)
- {
- divDataContext.Remove(thread);//从线程字典中移除
- db.Dispose();//释放数据资源
- }
- #endregion
- }
下面是DataContext基类,已经对SubmitChanges(SaveChanges)方法进行了优化,手动dispose上下文。
- /// <summary>
- /// Repository基类
- /// 所有linqTosql上下文对象都继承它
- /// </summary>
- 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 >
- || cSet.Updates.Count >
- || cSet.Deletes.Count > )
- && !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基类,代码如下:
- /// <summary>
- /// Test数据库基类
- /// Created By : 张占岭
- /// Created Date:2011-10-14
- /// Modify By:
- /// Modify Date:
- /// Modify Reason:
- /// </summary>
- 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
- /// <summary>
- /// 可以使用的数据库连接对象
- /// [xxb]
- /// </summary>
- protected dbDataContext db
- {
- get
- {
- return (dbDataContext)base._db;
- }
- }
- #endregion
- }
- }
OK,这就是改善之后的linq to sql架构的核心代码,主要体现在生成数据上下文对象上,及如何去避免并发冲突的产生,而对于并发冲突我们会在另一篇文章中做详细的说明。敬请期待!
LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对的更多相关文章
- PL/SQL那点事-->SqlSession operation; SQL []; ORA-01722: 无效数字
PL/SQL那点事-->SqlSession operation;SQL []; ORA-01722: 无效数字 出现这种情况,在网上查了很多方法:大致主要有两种方法帮助我们解决这个问题: 1. ...
- 使用Hive或Impala执行SQL语句,对存储在HBase中的数据操作
CSSDesk body { background-color: #2574b0; } /*! zybuluo */ article,aside,details,figcaption,figure,f ...
- 使用Hive或Impala执行SQL语句,对存储在Elasticsearch中的数据操作(二)
CSSDesk body { background-color: #2574b0; } /*! zybuluo */ article,aside,details,figcaption,figure,f ...
- 使用Hive或Impala执行SQL语句,对存储在Elasticsearch中的数据操作
http://www.cnblogs.com/wgp13x/p/4934521.html 内容一样,样式好的版本. 使用Hive或Impala执行SQL语句,对存储在Elasticsearch中的数据 ...
- sql语句 怎么从一张表中查询数据插入到另一张表中?
sql语句 怎么从一张表中查询数据插入到另一张表中? ----原文地址:http://www.phpfans.net/ask/MTc0MTQ4Mw.html 比如我有两张表 table1 字段 un ...
- sql存储过程通过ID删除两表中的数据。
CREATE OR REPLACE PROCEDURE del_p --建立名为del_p 的过程 IS CURSOR get_abid --简历名为get_abid的cursor 用来存放a表的id ...
- DRDS SQL 审计与分析——全面洞察 SQL 之利器
背景 数据库存储着系统的核心数据,其安全方面的问题在传统环境中已经成为泄漏和被篡改的重要根源.而在云端,数据库所面临的威胁被进一步的放大.因此,对云数据库的操作行为尤其是全量 SQL 执行记录的审计日 ...
- 【数据库-Azure SQL Database】如何创建事务复制将本地数据同步到 SQL Azure
Azure SQL DB 可以被配置成为 SQL Server 事务复制的一个订阅者( subscriber ). 主要应用场景有两种: 将您的数据迁移到 Azure SQL DB, 并且没有宕机时间 ...
- 利用反射自动生成SQL语句(仿Linq)
转:http://www.cnblogs.com/the7stroke/archive/2012/04/22/2465597.html using System; using System.Colle ...
随机推荐
- windows10-桌面图标不见了,资源管理器的桌面中可以看到??
问题描述: 1. 桌面的图标,在桌面上看不到, 但是在通过资源管理器可以看到, 图标仍然在桌面 2. 桌面仍然可以右击, 就是看不见新建或者拷贝到桌面的所有图标 解决方案: Google 后请参考: ...
- linux上的编译安装
计算机运行的程序都是二进制的代码,那么我们所用的编程语言都是自然语言中的字符,那么就需要有一种机制来将这些转化成二进制代码,那么根据转化机制不一样,编程语言(软件 产生的源头)分两大类 解释型 编译型 ...
- Quartus调用modelsim
1.Quartus 调用modelsim Test Bench Name :是test bench的文件名 Top Level module in test bench:test bench文件内的m ...
- String与StringBuffer的区别
首先,String和StringBuffer主要有2个区别: (1)String类对象为不可变对象,一旦你修改了String对象的值,隐性重新创建了一个新的对象,释放原String对象,StringB ...
- P1-概率论基础(Primer on Probability Theory)
2.1概率密度函数 2.1.1定义 设p(x)为随机变量x在区间[a,b]的概率密度函数,p(x)是一个非负函数,且满足 注意概率与概率密度函数的区别. 概率是在概率密度函数下对应区域的面积,如上图右 ...
- win7 解锁注册表
win7系统 各种百度,各种尝试,发现只此一种可以解锁 [Version] Signature=“$CHICAGO$” [DefaultInstall] DelReg=del [del] HKCU,S ...
- SublimeText为啥选择Python开发extension
真正优秀的软件是靠优秀的程序员开发出来的,反过来也一样,优秀的语言,平台,工具只有在优秀的程序员的手中才能显现出它的威力. 比如,Jon Skinner开发的SublimeText.桌面应用一般支持二 ...
- 怎样把windows中安装的程序列出来?
症状/问题我怎样把windows中安装的程序信息输出到一个文本文件中?解决方法使用 windows 操作系统中的命令:wmic就可以做到.下面的命令就可以把系统中安装的程序都输出到文件ProgramL ...
- html及css常用的单词
string? 字符串 boolean? 布尔数学体系,1,0 node? 节点,结 log? ? 日志,记录 console? 控制台 alert? ? 警报 document? 文档 write? ...
- GitLab的Gravatar头像服务不可用
由于www.gravatar.com在国内不可正常使用,导致我们搭建的GitLab在网页上会阻塞大量时间,并最终无法显示头像.我们可以将其替换成"多说"的头像服务.我使用的是CE ...