首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

走進 LINQ:How Do I (4) — 補遺篇(上)

     編輯:關於.NET

最近忙碌許久,本系列暫停更新。從今天起重啟「走進 LINQ」之旅。LINQ to SQL 核心用法已大體說明,尚有細節需補充。

強型別 DataContext

首篇提過 DataContext 是 LINQ to SQL 的入口點,幾乎所有操作都施加於此類別。使用 VS 設計器產生的程式碼中,會看到一個繼承自 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 表預存程序。只能套用在方法上。
  • Parameter:對應預存程序或函數的參數。
  • ResultType:指定回傳結果的型別,用於多重結果集情境。

範例 1:單一結果集預存程序

預存程序:

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;
}

呼叫方式:

ISingleResult<Post> posts = dbCtx.GetPostsByBlogId(1);
foreach (var p in posts) Console.WriteLine(p.Title);

範例 2:依參數回傳不同結果集

預存程序:

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<T>() 取得特定型別結果:

IMultipleResults results = dbCtx.GetBlogsOrPosts(1);
foreach (var b in results.GetResult<Blog>()) Console.WriteLine(b.Name);

範例 3:一次回傳多個結果集

預存程序:

CREATE PROCEDURE dbo.GetBblogsAndPosts
AS
SELECT * FROM blogs
SELECT * FROM posts
RETURN

.NET 方法對應方式同範例 2。

DataContext 其他實用方法

ExecuteCommand、ExecuteQuery<TResult>、Translate 三方法為與傳統 ADO.NET 整合而設計。

ExecuteCommand

執行 INSERT、UPDATE、DELETE。第一個參數接受格式化 SQL,第二個為參數陣列:

dbCtx.ExecuteCommand("insert into posts (blogid,title,body) values({0},{1},{2})", "2", "走進Linq-How do I(4)", "廢話一篇");

ExecuteQuery<TResult>

執行查詢,回傳 IEnumerable<T>:

IEnumerable<Post> posts = dbCtx.ExecuteQuery<Post>("select * from posts where postid = {0}", "1");
foreach (var post in posts) Console.WriteLine(post.Title);

Translate

將傳統 DataReader 轉換為 LINQ to SQL 物件,優點:

  1. 利用現有對應,免去 post.Title = dr[1].ToString() 等手動指派。
  2. 可使用查詢運算式語法。

自訂插入/更新/刪除行為

為提升效能或實作複雜邏輯,可覆寫預設行為。步驟:

  1. 撰寫預存程序(如 dbo.CreatePost)。
  2. 將資料表與預存程序拖入設計器。
  3. 右鍵資料表選「設定行為」,指定自訂預存程序處理插入/更新/刪除。

LINQ to SQL 交易處理

LINQ to SQL 內建支援樂觀並行交易,也可顯式啟動:

dbCtx.Transaction = dbCtx.Connection.BeginTransaction();
try
{
    dbCtx.ExecuteCommand("insert into posts(blogid,title,body) values({0},{1},{2})", "2", "走進Linq-How do I(4)", "廢話一篇");
    dbCtx.ExecuteCommand("insert into posts(blogid,title,body) values({0},{1},{2})", "3", "走進Linq-How do I(5)", "廢話兩篇");
    dbCtx.Transaction.Commit();
}
catch
{
    dbCtx.Transaction.Rollback();
}

BeginTransaction 可接受 IsolationLevel 指定隔離等級。跨多個 DataContext 的交易可使用 .NET 2.0 引入的 TransactionScope。

下一篇將討論 RowVersion 相關議題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved