5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结
一、多线程带来的问题 1、死锁问题 前面我们学习了Task的使用方法,其中Task的等待机制让我们瞬间爱上了它,但是如果我们在调用Task.WaitAll方法等待所有线程时,如果有一个Task一直不返回,会出现什么情况呢?当然,如果我们不做出来的话,程序会一直等待下去,那么因为这一个Task的死锁,导致其他的任务也无法正常提交,整个程序"死"在那里。下面我们来写一段代码,来看一下死锁的情况:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var t1 = Task.Factory.StartNew(() => { Console.WriteLine("Task 1 Start running..."); while(true) { System.Threading.Thread.Sleep(1000); } Console.WriteLine("Task 1 Finished!"); }); var t2 = Task.Factory.StartNew(() => { Console.WriteLine("Task 2 Start running..."); System.Threading.Thread.Sleep(2000); Console.WriteLine("Task 2 Finished!"); }); Task.WaitAll(t1,t2); |
这里我们创建两个Task,t1和t2,t1里面有个while循环,由于条件一直为TRUE,所以他永远也无法退出。运行程序,结果如下: 可以看到Task2完成了,就是迟迟等不到Task1,这个时候我们按回车是没有反应的,除非关掉窗口。如果我们在项目中遇到这种情况是令人很纠结的,因为我们也不知道到底发生了什么,程序就是停在那里,也不报错,也不继续执行。 那么出现这种情况我们该怎么处理呢?我们可以设置最大等待时间,如果超过了等待时间,就不再等待,下面我们来修改代码,设置最大等待时间为5秒(项目中可以根据实际情况设置),如果超过5秒就输出哪个任务出错了,代码如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
Task[] tasks = new Task[2]; var tasks[0] = Task.Factory.StartNew(() => { Console.WriteLine("Task 1 Start running..."); while(true) { System.Threading.Thread.Sleep(1000); } Console.WriteLine("Task 1 Finished!"); }); var tasks[1] = Task.Factory.StartNew(() => { Console.WriteLine("Task 2 Start running..."); System.Threading.Thread.Sleep(2000); Console.WriteLine("Task 2 Finished!"); }); Task.WaitAll(tasks,5000); for (int i = 0; i < tasks.Length;i++ ) { if (tasks[i].Status != TaskStatus.RanToCompletion) { Console.WriteLine("Task {0} Error!",i + 1); } } Console.Read(); |
这里我们将所有任务放到一个数组里面进行管理,调用Task.WaitAll的一个重载方法,第一个参数是Task[]数据,第二个参数是最大等待时间,单位是毫秒,这里我们设置为5000及等待5秒钟,就继续向下执行。下面我们遍历Task数组,通过Status属性判断哪些Task没有完成,然后输出错误信息。 2、SpinLock(自旋锁) 我们初识多线程或者多任务时,第一个想到的同步方法就是使用lock或者Monitor,然而在4.0 之后微软给我们提供了另一把利器——spinLock,它比重量级别的Monitor具有更小的性能开销,它的用法跟Monitor很相似,VS给的提示如下: 下面我们来写一个例子看一下,代码如下(关于lock和Monitor的用法就不再细说了,网上资料很多,大家可以看看):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
SpinLock slock = new SpinLock(false); long sum1 = 0; long sum2 = 0; Parallel.For(0, 100000, i => { sum1 += i; }); Parallel.For(0, 100000, i => { bool lockTaken = false; try { slock.Enter(ref lockTaken); sum2 += i; } finally { if (lockTaken) slock.Exit(false); } }); Console.WriteLine("Num1的值为:{0}", sum1); Console.WriteLine("Num2的值为:{0}", sum2); Console.Read(); |
输出结果如图: 这里我们使用了Parallel.For方法来做演示,Parallel.For用起来方便,但是在实际开发中还是尽量少用,因为它的不可控性太高,有点简单粗暴的感觉,可能带来一些不必要的"麻烦",最好还是使用Task,因为Task的可控性较好。 slock.Enter方法,解释如下: 3、多线程之间的数据同步 多线程间的同步,在用thread的时候,我们常用的有lock和Monitor,上面刚刚介绍了.Net4.0中一个新的锁——SpinLock(自旋锁),实际上,我们还可以将任务分成多块,由多个线程一起执行,最后合并多个线程的结果,如:求1到100的和,我们分10个线程,分别求1~10,……,90~100的和,然后合并十个线程的结果。还有就是使用线程安全集合,可参加第二天的文章。其实Task的同步机制做已经很好了,如果有特殊业务需求,有线程同步问题,大家可一起交流~~ 二、Task和线程池之间的抉择 我们要说的task的知识也说的差不多了,接下来我们开始站在理论上了解下“线程池”和“任务”之间的关系,我们要做到知其然,还要知其所以然。不管是说线程还是任务,我们都不可避免的要讨论下线程池,然而在.net 4.0以后,线程池引擎考虑了未来的扩展性,已经充分利用多核微处理器架构,只要在可能的情况下,我们应该尽量使用task,而不是线程池。 这里简要的分析下CLR线程池,其实线程池中有一个叫做“全局队列”的概念,每一次我们使用QueueUserWorkItem的使用都会产生一个“工作项”,然后“工作项”进入“全局队列”进行排队,最后线程池中的的工作线程以FIFO(First Input First Output)的形式取出,这里值得一提的是在.net 4.0之后“全局队列”采用了无锁算法,相比以前版本锁定“全局队列”带来的性能瓶颈有了很大的改观。那么任务委托的线程池不光有“全局队列”,而且每一个工作线程都有”局部队列“。我们的第一反应肯定就是“局部队列“有什么好处呢?这里暂且不说,我们先来看一下线程池中的任务分配,如下图: 线程池的工作方式大致如下,线程池的最小线程数是6,线程1~3正在执行任务1~3,当有新的任务时,就会向线程池请求新的线程,线程池会将空闲线程分配出去,当线程不足时,线程池就会创建新的线程来执行任务,直到线程池达到最大线程数(线程池满)。总的来说,只有有任务就会分配一个线程去执行,当FIFO十分频繁时,会造成很大的线程管理开销。 下面我们来看一下task中是怎么做的,当我们new一个task的时候“工作项”就会进去”全局队列”,如果我们的task执行的非常快,那么“全局队列“就会FIFO的非常频繁,那么有什么办法缓解呢?当我们的task在嵌套的场景下,“局部队列”就要产生效果了,比如我们一个task里面有3个task,那么这3个task就会存在于“局部队列”中, 如下图的任务一,里面有三个任务要执行,也就是产生了所谓的"局部队列",当任务三的线程执行完成时,就会从任务一种的队列中以FIFO的形式"窃取"任务执行 ,从而减少了线程管理的开销。这就相当于,有两个人,一个人干完了分配给自己的所有活,而另一个人却还有很多的活,闲的人应该接手点忙的人的活,一起快速完成。 从上面种种情况我们看到,这些分流和负载都是普通ThreadPool.QueueUserWorkItem所不能办到的,所以说在.net 4.0之后,我们尽可能的使用TPL,抛弃ThreadPool。 这是5天玩转C#并行和多线程编程系列的最后一篇了,当然还有很多东西没说到,如果真的想要玩转多线程,还是要多多努力学习的。大家在学习过程中有什么问题可以一起交流~~ 如果大家感觉我的博文对大家有帮助,请推荐支持一把,给我写作的动力。 from:http://www.tuicool.com/articles/2maqYrI
View Detailsc#使用多线程的几种方式示例详解
(1)不需要传递参数,也不需要返回参数 ThreadStart是一个委托,这个委托的定义为void ThreadStart(),没有参数与返回值。 复制代码代码如下: class Program{ static void Main(string[] args) { for (int i = 0; i < 30; i++) { ThreadStart threadStart = new ThreadStart(Calculate); Thread thread = new Thread(threadStart); thread.Start(); } Thread.Sleep(2000); Console.Read(); } public static void Calculate() { DateTime time = DateTime.Now;//得到当前时间 Random ra = new Random();//随机数对象 Thread.Sleep(ra.Next(10,100));//随机休眠一段时间 Console.WriteLine(time.Minute + ":" + time.Millisecond); } } (2)需要传递单个参数 ParameterThreadStart委托定义为void ParameterizedThreadStart(object state),有一个参数但是没有返回值。 复制代码代码如下: class Program{ static void Main(string[] args) { for (int i = 0; i < 30; i++) { ParameterizedThreadStart tStart = new ParameterizedThreadStart(Calculate); Thread thread = […]
View DetailsMySQL DATEDIFF() 函数
定义和用法 DATEDIFF() 函数返回两个日期之间的天数。 语法
|
1 |
DATEDIFF(date1,date2) |
date1 和 date2 参数是合法的日期或日期/时间表达式。 注释:只有值的日期部分参与计算。 实例 例子 1 使用如下 SELECT 语句:
|
1 |
SELECT DATEDIFF('2008-12-30','2008-12-29') AS DiffDate |
结果: DiffDate 1 例子 2 使用如下 SELECT 语句:
|
1 |
SELECT DATEDIFF('2008-12-29','2008-12-30') AS DiffDate |
结果: DiffDate -1 from:http://www.w3school.com.cn/sql/func_datediff_mysql.asp
View DetailsMySql四舍五入
FLOOR(X) 返回不大于X的最大整数值。 mysql> select FLOOR(1.23); -> 1 mysql> select FLOOR(-1.23); -> -2 注意返回值被变换为一个BIGINT! CEILING(X) 返回不小于X的最小整数值。 mysql> select CEILING(1.23); -> 2 mysql> select CEILING(-1.23); -> -1 注意返回值被变换为一个BIGINT! ROUND(X) 返回参数X的四舍五入的一个整数。 mysql> select ROUND(-1.23); -> -1 mysql> select ROUND(-1.58); -> -2 mysql> select ROUND(1.58); -> 2 注意返回值被变换为一个BIGINT! ROUND(X,D) 返回参数X的四舍五入的有D为小数的一个数字。如果D为0,结果将没有小数点或小数部分。 mysql> select ROUND(1.298, 1); -> 1.3 mysql> select ROUND(1.298, 0); -> 1 注意返回值被变换为一个BIGINT! from:http://www.cnblogs.com/youyou/archive/2005/11/07/270783.html
View Details卢庚戌
卢庚戌,1970年12月21日出生于辽宁省营口市,毕业于清华大学建筑系,中国流行男歌手,创作歌唱组合水木年华的主唱,民谣才子。为乐队团长、主唱、作词、作曲、编曲、编曲创意。 2010年水木年华签约英皇,成为英皇旗下的一员。代表作品有《蝴蝶花》、《一生有你》、《在他乡》、《完美世界》、《渴望就是力量》等。 早年经历 1989年以市理科状元的身份进入清华大学建筑系。 1994年大学毕业后,辞去工作一直追求音乐,却屡屡碰壁。直到2000年发行个人专辑《未来的未来》。 2001年组成水木年华至今,经历过两次人员变动。 2010年开始构思并创作剧本《怒放》,历经三年完成电影的拍摄和制作。 1989年从营口市高级中学以营口市理科第一名的成绩考取清华大学建筑系。入校后受校园原创音乐的影响喜欢上音乐,并开始学习吉他。 1990年参加校吉他大奖赛获得第二名。同年加入校文学社和文艺社团合唱队。 1991年与几个同学成立校园歌曲协会,在高校间频频举办演唱活动。当时经常参与活动的有后来成为校园民谣主将的高晓松、沈庆、郁冬等。同年开始尝试写歌。 1992年在校成立“梦中草原”合唱团,并获得当年北京市高校歌曲比赛一等奖。 1993年写出三重唱歌曲《成长》参加当年北京市高校歌曲比赛获得一等奖,此后常在各高校演出。 1994年参加中央电视台、北京电视台等晚会节目的录制。参加校园民谣的录制并成功举办“梦中草原”清华演唱会。同年毕业。 1995年-1997年在北京某设计院担任建筑设计师。 1998年成功举办个人清华快乐园演唱会,结识当时广州著名音乐人陈梓秋,在陈梓秋帮助下开始筹划个人专辑。 演艺经历 1999年制作个人专辑《未来的未来》。 2000年签约北京喜洋洋文化发展有限公司,同年发行个人专辑《未来的未来》。 2001年与校友李健成立“水木年华”演唱组。 2001年9月发行水木年华专辑《一生有你》,并获得当年几乎全部年度最佳新人奖。 2002年6月发行水木年华专辑《青春正传》,同年李健离队,缪杰、姚勇加入。 2003年1月发行水木年华专辑《新歌+精选》,并出版发行个人书籍《水木年华——音乐·清华·我》。同年姚勇离队。 2004年5月发行水木年华限量版专辑《毕业纪念册》;同年10月发行水木年华全新专辑《70.80》。 2005年5月发行水木年华DJ版专辑《跳舞专辑》。同年10月发行水木年华单曲《完美世界》(此歌曲为国内自主开发的大型网络游戏“完美世界”的主题曲)。 2006年4月发行水木年华专辑《生命狂想曲》;同年5月13日水木年华举行“生命之狂想”2006.5.13北京演唱会;7月发行水木年华演唱会唱片《完美世界水木年华生命之狂想2006.5.13北京演唱会》;10月水木年华为“共同关注希望工程—圆梦行动”创作主题歌“给我一双翅膀”,并发行水木年华宣传版单曲《给我一双翅膀》;12月发行水木年华精装版专辑《生命狂想曲三碟精装版》。 2007年5月发行水木年华专辑《双重幻想》,同年水木年华举行“完美时空最好的年华”2007水木年华全国巡回演唱会。 2008年2月发行水木年华演唱会唱片《完美时空最好的年华水木年华演唱会现场版》,同年5月发行水木年华宣传版EP《生命的挑战》。(此歌曲为水木年华为北京奥运创作的歌曲,也是央视栏目“想挑战吗?”的主题曲)。 2009年3月发行个人珍藏版专辑《未来的未来》。 2009年5月发行水木年华EP《启程》。 2009年9月发行水木年华EP《生命的意义》,并亲自执导此歌的MV。 2010年1月6日发行水木年华单曲《宝贝,你听到了吗?》(此歌曲为2009年儿童喜剧电影《火星宝贝之火星没事》的主题曲),1月9日水木年华签约英皇,成为英皇旗下的一员,05月11日发行水木年华全新专辑《启程》 ,12月发行水木年华单曲《新年快乐》。 2011年6日发行水木年华单曲《渴望就是力量》(此歌曲为增爱百事校园行活动主题曲)。 作品情况 个人作品 专辑曲目词曲补充说明 2000.08《未来的未来》(卢庚戌) 01. 《未来的未来》(词:卢庚戌 / 曲:卢庚戌 / 编曲:刘君利 / 贝司:刘君利 / 和声:卢庚戌 缪杰) 02. 《蝴蝶花》(词:卢庚戌 / 曲:卢庚戌 / 编曲:苏沐 / 吉他:刘林 / 大提琴:苏桐 / 和声:芭比娃娃) 03. 《游乐场》(词:卢庚戌 / 曲:卢庚戌 / 编曲:刘君利 / 吉他:刘君利 / 贝司:刘君利 / 和声:缪杰) 04. 《恋爱十日谈》(词:卢庚戌 / 曲:卢庚戌 / 编曲:卢庚戌 刘君利 / 吉他:卢庚戌 刘君利) 05. 《平安大街》(词:卢庚戌 / 曲:卢庚戌 / 编曲:刘君利 […]
View DetailsAsp.net+Mysql,查询出错:由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败
在网上看到的解决方案基本都是说host文件中127.0.0.1 localhost 的对应, 但我查看了host文件,并没有问题,纠结半天,拿查询语句在Mysql Workbench上执行,报了一个错,说是子查询包含多个结果,我去~!这很简单的一个错误asp.net竟然没能准确反馈。 于是在子查询语句后面加limit 1,Ok~ 所以,出现“由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败”这个错误时,有可能是查询语句有问题,而不是连接有问题。 from:http://blog.csdn.net/idoiknow/article/details/8923553
View DetailsNPOI读写Excel
1、整个Excel表格叫做工作表:WorkBook(工作薄),包含的叫页(工作表):Sheet;行:Row;单元格Cell。 2、NPOI是POI的C#版本,NPOI的行和列的index都是从0开始 3、POI读取Excel有两种格式一个是HSSF,另一个是XSSF。 HSSF和XSSF的区别如下: HSSF is the POI Project’s pure Java implementation of the Excel ’97(-2007) file format. XSSF is the POI Project’s pure Java implementation of the Excel 2007 OOXML (.xlsx) file format. 即:HSSF适用2007以前的版本,XSSF适用2007版本及其以上的。 下面是用NPOI读写Excel的例子:ExcelHelper封装的功能主要是把DataTable中数据写入到Excel中,或者是从Excel读取数据到一个DataTable中。 ExcelHelper类:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using NPOI.HSSF.UserModel; using System.IO; using System.Data; namespace NetUtilityLib { public class ExcelHelper : IDisposable { private string fileName = null; //文件名 private IWorkbook workbook = null; private FileStream fs = null; private bool disposed; public ExcelHelper(string fileName) { this.fileName = fileName; disposed = false; } /// <summary> /// 将DataTable数据导入到excel中 /// </summary> /// <param name="data">要导入的数据</param> /// <param name="isColumnWritten">DataTable的列名是否要导入</param> /// <param name="sheetName">要导入的excel的sheet的名称</param> /// <returns>导入数据行数(包含列名那一行)</returns> public int DataTableToExcel(DataTable data, string sheetName, bool isColumnWritten) { int i = 0; int j = 0; int count = 0; ISheet sheet = null; fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); if (fileName.IndexOf(".xlsx") > 0) // 2007版本 workbook = new XSSFWorkbook(); else if (fileName.IndexOf(".xls") > 0) // 2003版本 workbook = new HSSFWorkbook(); try { if (workbook != null) { sheet = workbook.CreateSheet(sheetName); } else { return -1; } if (isColumnWritten == true) //写入DataTable的列名 { IRow row = sheet.CreateRow(0); for (j = 0; j < data.Columns.Count; ++j) { row.CreateCell(j).SetCellValue(data.Columns[j].ColumnName); } count = 1; } else { count = 0; } for (i = 0; i < data.Rows.Count; ++i) { IRow row = sheet.CreateRow(count); for (j = 0; j < data.Columns.Count; ++j) { row.CreateCell(j).SetCellValue(data.Rows[i][j].ToString()); } ++count; } workbook.Write(fs); //写入到excel return count; } catch (Exception ex) { Console.WriteLine("Exception: " + ex.Message); return -1; } } /// <summary> /// 将excel中的数据导入到DataTable中 /// </summary> /// <param name="sheetName">excel工作薄sheet的名称</param> /// <param name="isFirstRowColumn">第一行是否是DataTable的列名</param> /// <returns>返回的DataTable</returns> public DataTable ExcelToDataTable(string sheetName, bool isFirstRowColumn) { ISheet sheet = null; DataTable data = new DataTable(); int startRow = 0; try { fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); if (fileName.IndexOf(".xlsx") > 0) // 2007版本 workbook = new XSSFWorkbook(fs); else if (fileName.IndexOf(".xls") > 0) // 2003版本 workbook = new HSSFWorkbook(fs); if (sheetName != null) { sheet = workbook.GetSheet(sheetName); if (sheet == null) //如果没有找到指定的sheetName对应的sheet,则尝试获取第一个sheet { sheet = workbook.GetSheetAt(0); } } else { sheet = workbook.GetSheetAt(0); } if (sheet != null) { IRow firstRow = sheet.GetRow(0); int cellCount = firstRow.LastCellNum; //一行最后一个cell的编号 即总的列数 if (isFirstRowColumn) { for (int i = firstRow.FirstCellNum; i < cellCount; ++i) { ICell cell = firstRow.GetCell(i); if (cell != null) { string cellValue = cell.StringCellValue; if (cellValue != null) { DataColumn column = new DataColumn(cellValue); data.Columns.Add(column); } } } startRow = sheet.FirstRowNum + 1; } else { startRow = sheet.FirstRowNum; } //最后一列的标号 int rowCount = sheet.LastRowNum; for (int i = startRow; i <= rowCount; ++i) { IRow row = sheet.GetRow(i); if (row == null) continue; //没有数据的行默认是null DataRow dataRow = data.NewRow(); for (int j = row.FirstCellNum; j < cellCount; ++j) { if (row.GetCell(j) != null) //同理,没有数据的单元格都默认是null dataRow[j] = row.GetCell(j).ToString(); } data.Rows.Add(dataRow); } } return data; } catch (Exception ex) { Console.WriteLine("Exception: " + ex.Message); return null; } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { if (fs != null) fs.Close(); } fs = null; disposed = true; } } } } |
测试代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; namespace NPOIExcelExample { class Program { static DataTable GenerateData() { DataTable data = new DataTable(); for (int i = 0; i < 5; ++i) { data.Columns.Add("Columns_" + i.ToString(), typeof(string)); } for (int i = 0; i < 10; ++i) { DataRow row = data.NewRow(); row["Columns_0"] = "item0_" + i.ToString(); row["Columns_1"] = "item1_" + i.ToString(); row["Columns_2"] = "item2_" + i.ToString(); row["Columns_3"] = "item3_" + i.ToString(); row["Columns_4"] = "item4_" + i.ToString(); data.Rows.Add(row); } return data; } static void PrintData(DataTable data) { if (data == null) return; for (int i = 0; i < data.Rows.Count; ++i) { for (int j = 0; j < data.Columns.Count; ++j) Console.Write("{0} ", data.Rows[i][j]); Console.Write("\n"); } } static void TestExcelWrite(string file) { try { using (ExcelHelper excelHelper = new ExcelHelper(file)) { DataTable data = GenerateData(); int count = excelHelper.DataTableToExcel(data, "MySheet", true); if (count > 0) Console.WriteLine("Number of imported data is {0} ", count); } } catch (Exception ex) { Console.WriteLine("Exception: " + ex.Message); } } static void TestExcelRead(string file) { try { using (ExcelHelper excelHelper = new ExcelHelper(file)) { DataTable dt = excelHelper.ExcelToDataTable("MySheet", true); PrintData(dt); } } catch (Exception ex) { Console.WriteLine("Exception: " + ex.Message); } } static void Main(string[] args) { string file = "..\\..\\myTest.xlsx"; TestExcelWrite(file); TestExcelRead(file); } } } |
Excel相关DLL下载:NPOI-Lib.rar 1.NPOI下载地址:http://npoi.codeplex.com/releases/view/38113 2.NPOI学习系列教程推荐:http://www.cnblogs.com/tonyqus/archive/2009/04/12/1434209.html 参考: http://www.cnblogs.com/Erik_Xu/archive/2012/06/08/2541957.html http://www.cnblogs.com/linzheng/archive/2010/12/20/1912137.html http://www.cnblogs.com/knowledgesea/archive/2012/11/16/2772547.html from:http://www.cnblogs.com/luxiaoxun/p/3374992.html
View DetailsEntity Framework – 直接执行数据库命令
原文地址: http://msdn.microsoft.com/en-us/library/gg715124(v=vs.103) 使用 EF 4.1 或者更新版本, 你可以直接执行任何数据库命令. 在本节介绍的方法允许你对数据库执行原生的 SQL 命令. 通过 SQL 查询语句获取实体对象集 DbSet 类中的 SqlQuery 方法允许你执行一个返回实体对象集的原生 SQL 查询. 默认情况下, 返回的对象集会被上下文跟踪; 这可以通过对方法返回的 DbSqlQuery 对象调用 AsNoTracking 方法取消.返回的结果集一般为 DbSet 所对应的类型, 否则即便是其派生类也无法返回. 如果所查询的表包含了其他实体类型的数据, 那么所执行的 SQL 语句应该被正确书写, 保证只返回指定类型实体的数据. 下面的例子使用 SqlQuery 方法执行了一个 SQL 查询, 返回一个 Department 类型的实例集.
|
1 2 3 4 5 |
1 using (var context = new SchoolEntities()) 2 { 3 var departments = context.Departments.SqlQuery( 4 "select * from Department").ToList(); 5 } |
译注: AsNoTracking 方法必须再查询执行前调用, 查询执行后调用无效. 通过 SQL 查询获取非实体对象集 通过 Database 类中的 SqlQuery 方法来执行原生 SQL 命令, 可以返回任何类型的实例, 包括 .Net 中的原生类型. 但获取的数据将不会被上下文对象跟踪, 即使我们用这个方法来检索实体对象. 如:
|
1 2 3 4 |
1 using (var context = new SchoolEntities()) 2 { 3 var names = context.Database.SqlQuery<string>("select Name from Department").ToList(); 4 } |
让数据库执行原生的非查询 SQL 命令 可以通过 Database 类中的 ExecuteSqlCommand 方法执行非查询命令. 例如:
|
1 2 3 4 |
1 using (var context = new SchoolEntities()) 2 { 3 context.Database.ExecuteSqlCommand("update Department set Name = 'Mathematics' where Name = 'Math'"); 4 } |
ExecuteSqlCommand 方法有时会被用在 Code First 创建的数据库的初始化函数中, 用来对数据库进行一些额外的配置 (例如, 设置索引). 需要注意的是, 上下文对象并不知道执行了 ExecuteSqlCommand […]
View Details如何在EF中直接运行SQL命令
相信不少使用EF的同志们已经知道如何在EF中运行SQL命令了。我在这里简单总结下,希望对大家学习EF有所帮助! 在 EF第一个版本(.NET 3.5 SP1)中,我们只能通过将ObjectContext.Connection转换为EntityConnection,再把 EntityConnection.StoreConnection转换为SqlConnection。有了这个SqlConnection,我们再创建 SqlCommand便能顺利运行SQL命令了。(个人觉得其实很烦,呵呵) 例如: EntityConnection entityConnection = (EntityConnection)ctx.Connection; DbConnection storeConnection = entityConnection.StoreConnection; DbCommand cmd = storeConnection.CreateCommand(); cmd.CommandType = System.Data.CommandType.StoredProcedure; cmd.CommandText = "[PRO_USER_DIGITALCARD_CHECK]"; 。。。。。。。 在EF4(.NET 4)中,我们有了全新的API:ObjectContext.ExecuteStoreCommand(…)和 ObjectContext.ExecuteStoreQuery<T>(…)。从函数名不难知道前者是为了执行某一并无返回集的SQL 命令,例如UPDATE,DELETE操作;后者是执行某一个查询,并可以将返回集转换为某一对象。 using (var ctx = new MyObjectContext()) { ctx.ExecuteStoreCommand("UPDATE Person SET Name = 'Michael' WHERE PersonID = 1"); } using (var ctx = new MyObjectContext()) { var peopleViews = ctx.ExecuteStoreQuery<PersonView>("SELECT PersonID, Name FROM Person"); } public class PersonView { public int PersonID { get; set; } public string Name { get; set; } } 现在有了EF4.1,API的名字又有了些许改变。如果说DbContext将ObjectContext做了包装,那么DbContext.Database就是对应于数据库端信息的封装。执行SQL命令也自然从Database类型开始。对应于ExecuteStoreCommand和ExecuteStoreQuery<T>的是Database.ExecuteSqlCommand和Database.SqlQuery<T>。 using (var ctx = new MyDbContext()) { ctx.Database.ExecuteSqlCommand("UPDATE Person SET Name = 'Michael' WHERE PersonID = 1"); } using (var ctx = new MyDbContext()) { var peopleViews = ctx.SqlQuery<PersonView>("SELECT PersonID, Name FROM Person").ToList(); } public class PersonView { public int PersonID { get; set; } public string Name { get; set; } } from:http://www.cnblogs.com/chengxiaohui/articles/2092001.html
View Details