系列文章導航:
走進Linq--Linq橫空出世篇
走進Linq-輝煌的背后
走進Linq-Linq大觀園
不能不說的C#特性-對象集合初始化器
不能不說的C#特性-匿名類型與隱式類型局部變量
不能不說的C#特性-擴展方法
不能不說的C#特性-匿名方法和Lambda表達式
不能不說的C#特性-迭代器(上)及一些研究過程中的副產品
不能不說的C#特性-迭代器(下),yield以及流的延遲計算
走進Linq-Linq to Objects(上)基礎篇
走進Linq-Linq to Objects(下)實例篇
走進Linq-Linq to SQL感性認識篇
走進Linq-Linq to SQL How do I(1)
走進Linq-Linq to SQL How do I(2)
走進Linq-Linq to SQL How do I(3)
走進Linq-How do I(4)拾遺補零篇第一節
走進Linq-Linq to SQL源代碼賞析 Table的獲取過程
走進Linq-Linq to SQL源代碼賞析之Provider的初始化
走進Linq-Linq to SQL源代碼賞析,通過Linq to SQL看Linq
最近很忙,真的很忙,所以這個系列好久沒更新了,從今天起我又開始了我的走進Linq之旅。Linq to SQL的用法基本上都說完了,還有一些細枝末節的地方需要聊聊。
強類型DataContext
在Linq to SQL的第一篇的時候就說道DataContext是一個入口點,我們使用Linq to SQL做的一些操作幾乎都是施加在這個類上的。在使用VS的設計器生成的代碼里,我們會看到一個從DataContext繼承的局部類,大家都習慣的將這個類稱之為強類型的DataContext,她對DataContext做了進一步的封裝。
今天我們先就對DataContext一些沒有介紹過的地方詳細討論一下。
首先我們先手寫一個強類型的DataContext:

強類型的DataContext
[Database(Name="CnBlogs")]
public class CnBlogsDataContext : DataContext

{
public CnBlogsDataContext(string fileOrConnectionString)
: base(fileOrConnectionString)

{ }
public CnBlogsDataContext(string fileOrConnectionString, MappingSource mapping)
: base(fileOrConnectionString, mapping)

{ }
public CnBlogsDataContext(IDbConnection conn)
: base(conn)

{ }
public CnBlogsDataContext(IDbConnection conn, MappingSource mapping)
: base(conn, mapping)

{ }

public Table<Post> Posts

{

get
{ return this.GetTable<Post>(); }
}

public Table<Blog> Blogs

{

get
{ return this.GetTable<Blog>(); }
}

public Table<User> Users

{

get
{ return this.GetTable<User>(); }
}

[Function(Name = "dbo.GetPostsByBlogId")]
public ISingleResult<Post> GetPostsByBlogId(
[Parameter(Name="blogid",DbType="int")]
int blogid)

{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), blogid);
return (ISingleResult<Post>)result.ReturnValue;
}

[Function(Name = "dbo.GetBblogsOrPosts")]
[ResultType(typeof(Blog))]
[ResultType(typeof(Post))]
public IMultipleResults GetBlogsOrPosts(
[Parameter(Name = "kind", DbType = "int")]
int kind)

{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)MethodInfo.GetCurrentMethod()), kind);
return (IMultipleResults)result.ReturnValue;
}

[Function(Name = "dbo.GetBblogsAndPosts")]
[ResultType(typeof(Blog))]
[ResultType(typeof(Post))]
public IMultipleResults GetBlogsOrPosts()

{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)MethodInfo.GetCurrentMethod()));
return (IMultipleResults)result.ReturnValue;
}
}
在這個類里出現了四個前面沒有看到的特性:Database,Function,Parameter,ResultType至于Database就不用說了,就是做數據庫映射的。下面對其它三個做一些討論:
Function、Parameter和ResultType
Linq to SQL不僅僅能做字段與屬性之間的映射,還可以將存儲過程或用戶自定義方法與.net里的方法之間做映射,功能是不是很強大?這個映射就是通過Function和Parameter共同完成的。
Function有兩個屬性IsComposable和Name,Name就是用來指定數據庫中存儲過程或者用戶自定義方法的名字,當IsComposable為true的時候,則表明該方法對應著一個用戶自定義方法,否則對應一個存儲過程,默認是false。Function特性只能放在方法上面。
Parameter就是用來映射存儲過程或方法接受的參數。
還是用例子來說明:
假設有這樣的一個存儲過程,通過blogid找出其所有的隨筆
ALTER PROCEDURE dbo.GetPostsByBlogId
(
@blogid int
)
AS
SELECT postid,blogid,title,body,createdate FROM posts WHERE blogid = @blogid
RETURN
我要在.net里寫一個方法來對應這個存儲過程
[Function(Name = "dbo.GetPostsByBlogId")]
public ISingleResult<Post> GetPostsByBlogId(
[Parameter(Name="blogid",DbType="int")]
int blogid)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), blogid);
return (ISingleResult<Post>)result.ReturnValue;
}
現在你可以以調用.net方法的形式直接調用這個方法來調用存儲過程

Code
ISingleResult<Post> posts = dbCtx.GetPostsByBlogId(1);
foreach (var p in posts)
{
Console.WriteLine(p.Title);
}
這樣就將存儲過程封裝成.NET的方法了,調用看看:

使用存儲過程的時候,我們往往使用一個條件參數,根據條件參數的不同返回不同的結果集:
ALTER PROCEDURE dbo.GetBblogsOrPosts
(
@kind int,
)
AS
if @kind = 1
SELECT * FROM blogs
ELSE
SELECT * FROM posts
RETURN
在.NET里使用這樣的方法映射:
[Function(Name = "dbo.GetBblogsOrPosts")]
[ResultType(typeof(Blog))]
[ResultType(typeof(Post))]
public IMultipleResults GetBlogsOrPosts(
[Parameter(Name = "kind", DbType = "int")]
int kind)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)MethodInfo.GetCurrentMethod()), kind);
return (IMultipleResults)result.ReturnValue;
}
返回一個ImultipleResults對象,該對象有一個GetResult方法:
IMultipleResults results = dbCtx.GetBlogsOrPosts(1);
foreach (var b in results.GetResult<Blog>())
{
Console.WriteLine(b.Name;
}
除了支持這種存儲過程外,還支持這樣的:
CREATE PROCEDURE dbo.GetBblogsAndPosts
AS
SELECT * FROM blogs
SELECT * FROM posts
RETURN
使用方法還是和上面的一樣。