来自:http://www.yaosansi.com/post/1380.html
记录LINQ生成的SQL语句是常用的调试方式,而且能根据需要来优化LINQ生成的SQL语句,更能了深入的了解LINQ.
DataContext的Log属性来将LINQ to SQL生成的SQL语句格式化.
一.控制台程序(Console)
dataContext.Log = Console.Out;
二.利用GetCommand方法
dataContext.GetCommand(query).CommandText;
三.使用LINQPad (官方网站)
LINQPad支持C# 3.0 和 Framework 3.5的全部功能:
- LINQ to SQL
- LINQ to Objects
- LINQ to XML
更多介绍请参考李永京的学习LINQ工具:LINQPad
下载地址:http://www.albahari.com/LINQPad.exe
四.LINQ to SQL Debug Visualizer
ScottGu的LINQ to SQL Debug Visualizer可以在Debug过程中查看SQL语句.
介绍:http://weblogs.asp.net/scottgu/archive/2007/07/31/linq-to-sql-debug-visualizer.aspx
下载:http://www.scottgu.com/blogposts/linqquery/SqlServerQueryVisualizer.zip
安装方法
1. 关闭 VS2008。
2. 将压缩包中的 SqlServerQueryVisualizer.dll 拷贝到 \Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers。
3. 重启 VS2008 即可。
五.DebuggerWriter工具类
由于Console.Out方法在ASP.NET程序不起作用.
Kris Vandermotten 已经创建好了一个这个工具类, 你只要使用这样的语法:
MyDataContext db = new MyDataContext();
db.Log = new DebuggerWriter();
asp.net可以选择将Log信息直接发送到Debug的输出窗口.
源码:
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
namespace Vandermotten.Diagnostics
{
/**//// <summary>
/// Implements a <see cref="TextWriter"/> for writing information to the debugger log.
/// </summary>
/// <seealso cref="Debugger.Log"/>
public class DebuggerWriter : TextWriter
{
private bool isOpen;
private static UnicodeEncoding encoding;
private readonly int level;
private readonly string category;
/**//// <summary>
/// Initializes a new instance of the <see cref="DebuggerWriter"/> class.
/// </summary>
public DebuggerWriter()
: this(0, Debugger.DefaultCategory)
{
}
/**//// <summary>
/// Initializes a new instance of the <see cref="DebuggerWriter"/> class with the specified level and category.
/// </summary>
/// <param name="level">A description of the importance of the messages.</param>
/// <param name="category">The category of the messages.</param>
public DebuggerWriter(int level, string category)
: this(level, category, CultureInfo.CurrentCulture)
{
}
/**//// <summary>
/// Initializes a new instance of the <see cref="DebuggerWriter"/> class with the specified level, category and format provider.
/// </summary>
/// <param name="level">A description of the importance of the messages.</param>
/// <param name="category">The category of the messages.</param>
/// <param name="formatProvider">An <see cref="IFormatProvider"/> object that controls formatting.</param>
public DebuggerWriter(int level, string category, IFormatProvider formatProvider)
: base(formatProvider)
{
this.level = level;
this.category = category;
this.isOpen = true;
}
protected override void Dispose(bool disposing)
{
isOpen = false;
base.Dispose(disposing);
}
public override void Write(char value)
{
if (!isOpen)
{
throw new ObjectDisposedException(null);
}
Debugger.Log(level, category, value.ToString());
}
public override void Write(string value)
{
if (!isOpen)
{
throw new ObjectDisposedException(null);
}
if (value != null)
{
Debugger.Log(level, category, value);
}
}
public override void Write(char[] buffer, int index, int count)
{
if (!isOpen)
{
throw new ObjectDisposedException(null);
}
if (buffer == null || index < 0 || count < 0 || buffer.Length - index < count)
{
base.Write(buffer, index, count); // delegate throw exception to base class
}
Debugger.Log(level, category, new string(buffer, index, count));
}
public override Encoding Encoding
{
get
{
if (encoding == null)
{
encoding = new UnicodeEncoding(false, false);
}
return encoding;
}
}
public int Level
{
get { return level; }
}
public string Category
{
get { return category; }
}
}
}
六.将LINQ to SQL生成的SQL语句写入日志文件
DataContext.Log是System.IO.TextWriter类型,所以你可以用以下的方法来做.
StreamWriter sw = new StreamWriter(
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "log.txt"));
dBLinqDataContext.Log = sw;
var query = dataContext.Customers.Single<Customer>(c=>c.CustomerID.Contains("s"))
.Skip(0).Take(10).ToList();
sw.Flush();
sw.Close();
但以上方法有个缺点,就是需要在每个实现的方法中都写这么多代码.使用起来太不方便.参照dataContext.Log = Console.Out的表现形式
由是有了FileLog类.(当然,FileLog类除了此功能还有一些基本的记录日志的方法)
使用时直接dataContext.Log = Yaosansi.IO.FileLog.Out;即可. 默认会在桌面上生成一个名叫UnNameFile.txt的文件.
当然如果你不想使用默认的文件名和路径也可以使用dataContext.Log =new Yaosansi.IO.FileLog("FileName")的方式.
下面是FileLog类的源码:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace Yaosansi.IO
{
/**//// <summary>
/// 文件操作
/// </summary>
public class FileLog : TextWriter
{
构造函数#region 构造函数
/**//// <summary>
///
/// </summary>
/// <param name="fileName">文件名[文件路径使用默认路径]</param>
public FileLog(string fileName)
: this(fileName,string.Empty,false)
{
}
/**//// <summary>
///
/// </summary>
/// <param name="fileName">文件名</param>
/// <param name="filePath">文件路径</param>
/// <param name="deleteExistingFile">是否删除已经存在的文件</param>
public FileLog(string fileName,string filePath, bool deleteExistingFile):this(fileName,filePath,long.MaxValue)
{
if (deleteExistingFile)
{
DeleteFile();
}
}
/**//// <summary>
///
/// </summary>
/// <param name="fileName">文件名</param>
/// <param name="filePath">文件路径</param>
/// <param name="fileSize">文件大小[单位:bytes]超出此大小将自动删除文件(使用longong.MaxValue例外)</param>
///
public FileLog(string fileName, string filePath, long fileSize)
{
if (!string.IsNullOrEmpty(fileName))
{
FileName = fileName;
}
else
{
FileName = "UnNameFile.txt";
}
if (!string.IsNullOrEmpty(filePath))
{
FilePath = filePath;
}
else
{
FilePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
}
FileSize = fileSize;
}
#endregion
重写TextWriter#region 重写TextWriter
public override Encoding Encoding
{
get
{
return new UnicodeEncoding(false, false);
}
}
public override void Write(char value)
{
WriteFile(value.ToString());
}
public override void Write(string value)
{
if (value != null)
{
WriteFile(value);
}
}
public override void Write(char[] buffer, int index, int count)
{
if (buffer == null || index < 0 || count < 0 || buffer.Length - index < count)
{
base.Write(buffer, index, count);
}
WriteFile(new string(buffer, index, count));
}
#endregion
属性#region 属性
/**//// <summary>
/// 文件名
/// </summary>
public string FileName { set; get; }
/**//// <summary>
/// 获取文件全名[包含路径]
/// </summary>
public string FullFileName
{
get
{
return FilePath + "\\" + FileName;
}
}
/**//// <summary>
/// 定义文件大小
/// </summary>
public long FileSize { set; get; }
/**//// <summary>
/// 文件路径;
/// </summary>
public string FilePath
{
set;
get;
}
/**//// <summary>
/// FileLog Factory
/// </summary>
public static FileLog Out
{
get
{
return new FileLog("");
}
}
#endregion
方法#region 方法
/**//// <summary>
/// 删除文件
/// </summary>
/// <returns></returns>
public bool DeleteFile()
{
bool succeed = false;
try
{
if (File.Exists(FullFileName))
{
File.Delete(FullFileName);
succeed = true;
}
}
catch { }
return succeed;
}
/**//// <summary>
/// 仅记录当前时间及分隔符
/// </summary>
public void WirteTime()
{
string message = "\r\n-------------------------------------------------------\r\n" +
"时间:" + DateTime.Now.ToString() + "\r\n" +
"-------------------------------------------------------";
WriteFile(message);
}
/**//// <summary>
/// 写文件
/// </summary>
/// <param name="Message"></param>
public void WriteFile(string Message)
{
StreamWriter sw = null;
try
{
//如果文件目录不存在,则创建
if (!Directory.Exists(FilePath))
{
Directory.CreateDirectory(FilePath);
}
//超过一定大小自动删除文件
if (FileSize != long.MaxValue)
{
FileInfo finfo = new FileInfo(FullFileName);
if (finfo.Exists && finfo.Length > FileSize)
{
finfo.Delete();
}
}
if (!File.Exists(FullFileName))
{
sw = File.CreateText(FullFileName);
}
else
{
sw = File.AppendText(FullFileName);
}
sw.WriteLine(Message);
sw.Flush();
}
catch (Exception ee)
{
Console.WriteLine("文件没有打开,详细信息如下:" + ee.ToString());
throw (new Exception("文件没有打开,详细信息如下:" + ee.ToString()));
}
finally
{
sw.Close();
sw.Dispose();
}
}
#endregion
}
}