Linq方便了我们对数据库的操作,直接用C#的语法操作数据库。但Linq也隐藏了实际执行的SQL语句,封装是好事,可是有时候还是不得不了解Linq具体对数据库的操作。比如,只有查看实际的SQL语句才能对数据库或查询语句做优化,而且在调试时不能查看SQL是很郁闷的事情。

有下面几种方法来挖掘出操作中所使用的Sql语句:



1、获取Query所对应的SqlCommand对象:



  在开发过程中,我们可以通过Query获得对应的Sql Command对象。请看如下代码:



AdventureWorksDataContext 
  new AdventureWorksDataContext(); 
  
var 
  from p in 
  
where 
  
select new 
  
foreach 
  var p in 
  
{ 
  
Console.WriteLine(p); 
  
} 
  
  
  
DbCommand 
   cmd = db.GetCommand(products); 
  
  
  
Console 
  .WriteLine("------------"); 
  
Console 
  .WriteLine("Command Text: \n{0}", cmd.CommandText); 
  
  
  
Console 
  .WriteLine("------------"); 
  
Console 
  .WriteLine("Command Type: \n{0}", cmd.CommandType); 
  
  
  
Console 
  .WriteLine("------------"); 
  
Console 
  .WriteLine("Command Parameters:"); 
  
foreach 
  DbParameter p in 
  
{ 
  
Console.WriteLine("{0}: {1}", p.ParameterName, p.Value); 
  
} 
  
  
  
Console 
  .ReadLine();


  
输出结果如下:



Command Text: 
  
 SELECT [t0].[ProductID], [t0].[Name] 
  
 FROM [Production].[Product] AS [t0] 
  
 WHERE [t0].[ProductID] = @p0 
  
 ------------ 
  
 Command Type: 
  
 Text 
  
 ------------ 
  
 Command Parameters: 
  
 @p0: 3


可以看到,无论是Sql语句或是参数都被打印了出来。事实上,由于我们得到了完整的SqlCommand对象,我们可以获取的信息并不止上述这些。



2、使用LINQ to SQL Debug Visualizer:



  使用LINQ to SQL Debug Visiualizer,我们可以在调试程序时直观地获得Query所对应的Sql语句以及参数,而不必获得SqlCommand对象并打印信息。具体使用方法详见 Scott Gu的这篇 博文



3、使用DataContext的Log功能:



  DataContext自带的Log属性为一个TextWriter类型的对象,如果我们设置了这个属性,则DataContext所有的 操作将会通过这个TextWriter对象输出。与比上述两种方法相比,这个方法的优势在于DataContext所执行的所有语句,无论SELECT、 INSERT、UPDATE或者是DELETE都会被输出;而上面的两种做法只能得到Query的信息,也就是SQL语句的SELECT操作。



  请看如下代码,下面的代码将AdventureWorksDataContext对象的所有操作输出至Console:

AdventureWorksDataContext 
  new AdventureWorksDataContext(); 
  
db.Log = Console.Out; 
  
  
  
Product 
  from p in 
  
where 
  
select 
  
  
  
product.Name = "Hello World"; 
  
db.SubmitChanges(); 
  
  
  
Console 
  .ReadLine();


输出结果如下:

SELECT TOP (1) [t0].[ProductID], [t0].[Name], [t0].[ProductNumber], [t0].[MakeFl 
  
 ... 
  
 edDate], [t0].[rowguid], [t0].[ModifiedDate] 
  
 FROM [Production].[Product] AS [t0] 
  
 WHERE [t0].[ProductID] = @p0 
  
 -- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1] 
  
 -- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1 
  

 UPDATE [Production].[Product] 
  
 SET [Name] = @p11 
  
 WHERE ([ProductID] = @p0) AND ([Name] = @p1) AND ([ProductNumber] = @p2) AND (NO 
  
 ... 
  
 NULL) AND ([rowguid] = @p9) AND ([ModifiedDate] = @p10) 
  
 -- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1] 
  
 ... 
  
 -- @p11: Input NVarChar (Size = 11; Prec = 0; Scale = 0) [Hello World] 
  
 -- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1


  
在这里我省略了大部分的输出,不过从上面的片断中我们已经可以看到SELECT和UPDATE操作所使用的Sql语句以及参数都被打印了出来。这就是我们可以利用的调试信息。



4、使用Sql Server Profiler:



  这个是我推荐的方法,比1,3方便,而且不可能漏掉任何信息。Sql Profiler的用法就不说了,大家应该都用过,但和监视一般的SQL还是有点地方需要注意。

aaaDataContext  
   db = new aaaDataContext(); 
   
aaa a = new 
   aaa(); 
   
var q = 
   
             
   from p 
   in context.aaa 
   
             
   where p.a.StartsWith("a") == 
   true 
   
             
   select p.id; 
   

int? a1 = q.First(); 
   
  
 上面这段代码Linq不是直接将它转换成"select id from aaa where....."而是转换成 
  

exec sp_executesql N'SELECT TOP (1) [t0].[id] 
   
 FROM [dbo].[aaa] AS [t0] 
   
 WHERE [t0].[a] LIKE @p0',N'@p0 nvarchar(2)',@p0=N'a%'



int? a1 = q.First();执行时,sql语句才真正被执行。