1. 程式人生 > >C#與SQL Server儲存過程之一(建立):使用C#建立SQL Server的儲存過程

C#與SQL Server儲存過程之一(建立):使用C#建立SQL Server的儲存過程

 

通常,開發人員使用的是T-SQL來建立SQL Server的儲存過程、函式和觸發器。而現在的SQL Server 2005已經完全支援.NET通用語言執行時(CLR)了。這就意味著,你可以使用.NET的語言,如C#VB.NET之類的來開發SQL Server的儲存過程、函式和觸發器。 SQL Server CLR 的整合給我們帶來了n多好處,如實時編譯、型別安全、增強的安全性以及增強的程式設計模型等。本文中,我將向大家演示如何使用C#建立SQL Server的儲存過程。

背景

我們在使用SQL Server儲存過程時,最常做的工作就是從資料庫中讀取或儲存資料。其常用應用如下:

執行一些簡單的邏輯,沒有任何返回值。

也沒有輸出引數。執行一些邏輯,並通過一個或更多的輸出引數返回結果。執行一些邏輯,並返回從表中讀取的一條或多條記錄。執行一些邏輯,並返回一行或多行記錄。這些記錄不是從表中讀取的,而是你自定義的一些資料行。

為了演示如何用C#開發出這幾種應用的SQL Server儲存過程,我將一個一個地舉出示例。

啟用CLR整合

在你開始用C#寫儲存過程之前,必須要啟用你的SQL ServerCLR整合特性。預設情況它是不啟用的。開啟你的SQL Server Management Studio並執行如下指令碼。

sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO

這裡,我們執行了系統儲存過程“sp_configure”,為其提供的兩個引數分別為:“clr enabled”“1”。如果要停用CLR整合的話也是執行這個儲存過程,只不過第二個引數要變為“0”而已。另外,為了使新的設定產生效果,不要忘記呼叫“RECONFIGURE”

SQL Server專案

現在開啟Visual Studio,並從檔案選單中選擇新建專案新建專案對話方塊中選擇“Visual C#”下的“Database”然後選擇“SQL Server專案模板。


起好專案名稱後就單擊確定按鈕。

很快,你所建立的專案就要求你選擇一個SQL Server資料庫。


按照提示一步一步地做就好了,就算你選擇了取消,也可以在

專案”–“屬性對話方塊中再一次選擇資料庫。舉個例子,假如你的電腦上有一個“北風貿易”資料庫,那麼就在新建資料庫引用對話方塊中選中它,然後單擊確定按鈕。之後,SQL Server專案在部署的時候就會將我們開發的儲存過程寫入這個資料庫(繼續往後看你就清楚是怎麼回事了)。

接下來,右鍵單擊你新建的這個專案,選擇新增”-“儲存過程然後將會出現如下圖所示的對話方塊:


選擇儲存過程模板,並起一個合適的名字,然後單擊新增按鈕。

新增完後你就會發現,實際上這是建立了一個已經匯入了需要用到的名稱空間的類。

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

注意一下加粗顯示的名稱空間(譯者注:後兩個using)。 System.Data.SqlTypes名稱空間包含了很多不同的型別,它們可以用來代替SQL Server的資料型別。 Microsoft.SqlServer.Server名稱空間下的類負責SQL ServerCLR整合。

說明:本程式操作“北風貿易”資料庫,“訂貨主檔”表,表內含有的欄位依次是:訂單號碼(int),送貨城市(nvarchar(15)) …其他欄位省略。

沒有返回值的儲存過程

在這一節中,我們將會看到如何寫一個執行了一些邏輯,但是卻沒有任何返回值和輸出引數的儲存過程。在這個例子裡,我們將建立一個名為“ChangeCityName”的儲存過程,它用來修改“訂貨主檔”表中“送貨城市”欄位的值。這個儲存過程需要兩個引數 –ID(需要更改“送貨城市”的“訂單號碼”ID)和City(新的“送貨城市”)。 “ChangeCityName”儲存過程完成後的程式碼如下:Procedure1

[Microsoft.SqlServer.Server.SqlProcedure]

public static void ChangeCityName(SqlInt32 ID, SqlStringCity)

{

// 在此處放置程式碼

SqlConnection con = new SqlConnection("context connection = true");

con.Open();

SqlCommand cmd = new SqlCommand();

cmd.Connection = con;

cmd.CommandText = "update 訂貨主檔 set 送貨城市[email protected] where 訂單號碼[email protected]";

SqlParameter p1 = new SqlParameter("@City", City);

SqlParameter p2 = new SqlParameter("@ID", ID);

cmd.Parameters.Add(p1);

cmd.Parameters.Add(p2);

int row = cmd.ExecuteNonQuery();

con.Close();

SqlContext.Pipe.Send(row.ToString());

}

};

仔細看一下這個ChangeCityName ()方法。它是一個靜態方法並且沒有返回值(void)。它需要兩個名為IDCity的引數。請注意這兩個引數的資料型別是SqlInt32SqlString SqlString可以用來代替SQL Server中的nvarchar資料型別。這個方法用了一個[SqlProcedure]屬性來修飾。該屬性用於標記ChangeCityName()方法是一個SQL Server儲存過程。

在方法內我們建立了一個SqlConnection物件,並設定其連線字串為“context connection = true”上下文連線可以讓你使用當前登入到資料庫的使用者作為你的登入資料庫的驗證資訊。本例中,ChangeCityName()方法將會轉換為儲存過程,然後儲存到“北風貿易”資料庫裡。所以在這裡的上下文連線指的就是“北風貿易”資料庫。這樣你就不需要再寫任何關於登入資料庫的驗證資訊了。

接下來是開啟資料庫連線。然後通過設定SqlCommand物件的ConnectionCommandText屬性,讓其執行更新操作。同時,我們還需要設定兩個引數。這樣通過呼叫ExecuteNonQuery()方法就可以執行更新操作了。再接下來就是關閉連線。

最後,將ExecuteNonQuery()方法的返回值傳送到客戶端。當然你也可以不做這一步。現在我們來了解一下SqlContext類的使用。 SqlContext類用於在服務端和客戶端之間傳遞處理結果。本例使用了Send()方法傳送一個字串返回給呼叫者。

返回從表中讀取的一條或多條記錄的儲存過程

我們在使用儲存過程時,經常會SELECT一條或多條記錄。你可以採用兩種方法來建立這樣的儲存過程。

首先我們建立一個名為GetAllCustomers()的方法,程式碼如下:Procedure2.1

[Microsoft.SqlServer.Server.SqlProcedure]

public static void GetAllInfo()

{

SqlConnection con = new SqlConnection("context connection = true");

SqlCommand cmd = new SqlCommand();

cmd.Connection = con;

cmd.CommandText = "Select * from 訂貨主檔";

con.Open();

SqlDataReader reader = cmd.ExecuteReader();

SqlContext.Pipe.Send(reader);

reader.Close();

con.Close();

}

這個GetAllInfo ()方法用了一個[SqlProcedure]屬性來修飾。在方法內建立一個SqlConnection和一個SqlCommand物件。然後使用ExecuteReader()方法來執行SELECT語句。接下來用Send()方法將取得的SqlDataReader資料傳送到客戶端。最後就是關閉SqlDataReaderSqlConnection在這種方法中,是我們自己建立的SqlDataReader

其實,我們也可以把這個任務交給SqlContext類去完成,程式碼如下:Procedure2.2

[Microsoft.SqlServer.Server.SqlProcedure]

public static void GetAllInfoByID(SqlInt32 ID)

{

SqlConnection con = new SqlConnection("context connection=true");

con.Open();

SqlCommand cmd = new SqlCommand();

cmd.Connection = con;

cmd.CommandText = "select * from 訂貨主檔 where 訂單號碼[email protected]";

SqlParameter p1 = new SqlParameter("@p1", ID);

cmd.Parameters.Add(p1);

SqlContext.Pipe.ExecuteAndSend(cmd);

con.Close();

}

GetAllInfoByID ()方法需要一個引數 –ID,它將從“訂貨主檔”表中返回某行的記錄。這個方法內的程式碼,除了ExecuteAndSend()方法外,你應該都已經比較熟悉了。 ExecuteAndSend()方法接收一個SqlCommand物件作為引數,執行它就會返回資料集給客戶端。

有輸出引數的儲存過程

我們在使用儲存過程時,經常會通過輸出引數返回一個經過計算的值。所以,現在讓我們來看一看如何建立具有一個或多個輸出引數的儲存過程。Procedure3

[Microsoft.SqlServer.Server.SqlProcedure]

public static void GetCityName(SqlInt32 ID, out SqlStringCity)

{

SqlConnection con = new SqlConnection("context connection=true");

con.Open();

SqlCommand cmd = new SqlCommand();

cmd.Connection = con;

cmd.CommandText = "Select送貨城市 from訂貨主檔 where訂單號碼[email protected]";

SqlParameter id = new SqlParameter("@ID", ID);

cmd.Parameters.Add(id);

object obj = cmd.ExecuteScalar();

con.Close();

City = obj.ToString();

}

這是一個名為GetCityName ()的方法,它需要兩個引數。第一個引數是ID,它是一個輸入引數;第二個引數是City,它是一個輸出引數(用關鍵字out來指明)。這兩個引數是SqlInt32SqlString型別的。GetCityName ()方法會接收一個ID引數,然後返回City(作為輸出引數)。

該方法內的程式碼首先設定了SqlConnectionSqlCommand物件。然後,使用ExecuteScalar()方法來執行SELECT語句。 ExecuteScalar()方法返回的值是一個object型別,它其實就是公司名稱。最後將輸出引數City設定為這個值。

返回一行或多行自定義資料的儲存過程

我們在使用儲存過程時,更多的還是從某些表中讀取資料。但是,某些情況下我們需要的資料可能不在任何表裡。例如,你可能會基於某些計算來生成一個數據表格。因為它的資料不是從表中獲得的,所以上面的方法就不在適用了。幸運的是,SQL ServerCLR整合特性給我們提供了一個解決這個問題的方法。請看如下程式碼:Procedure4.1

[Microsoft.SqlServer.Server.SqlProcedure]

public static void GetRow()

{

SqlMetaData[] metadata = new SqlMetaData[2];

metadata[0] = new SqlMetaData("ID", SqlDbType.Int);

metadata[1] = new SqlMetaData("City", SqlDbType.NVarChar, 15);

SqlDataRecord record = new SqlDataRecord(metadata);

record.SetInt32(0, 10248);

record.SetString(1, "北京市");

SqlContext.Pipe.Send(record);

}

GetRow()方法會返回一條記錄併發送給客戶端。這個方法首先聲明瞭一個SqlMetaData物件。當你要用到自定義列的時候,就可以使用這個SqlMetaData類。在我們的示例中,建立了兩個型別為NVarChar,長度為15的列。然後建立了一個SqlDataRecord物件。 SqlDataRecord類可以用來表示一個自定義行。它的建構函式需要一個SqlMetaData陣列作為引數。 SqlDataRecord物件的SetString()方法用來設定列的值。另外,還有許多不同的類似SetString()這樣的方法,可以用來處理不同的資料型別。最後,呼叫Send()方法將SqlDataRecord物件傳送到客戶端。

在上面的示例中,我們只返回了一行資料給呼叫者。那麼,如果要返回多行呢?請看下面的程式碼:Procedure4.2

[Microsoft.SqlServer.Server.SqlProcedure]

public static void GetMultipleRow()

{

SqlMetaData[] metadata = new SqlMetaData[2];

metadata[0] = new SqlMetaData("ID", SqlDbType.Int);

metadata[1] = new SqlMetaData("City", SqlDbType.NVarChar, 15);

SqlDataRecord record = new SqlDataRecord(metadata);

SqlContext.Pipe.SendResultsStart(record);

record.SetInt32(0, 10249);

record.SetString(1, "天津市");

SqlContext.Pipe.SendResultsRow(record);

record.SetInt32(0, 10250);

record.SetString(1, "天津市");

SqlContext.Pipe.SendResultsRow(record);

SqlContext.Pipe.SendResultsEnd();

}

GetMultipleRow()方法將會返回多個SqlDataRecord物件到客戶端。接下來建立自定義列和設定列的值都和之前的例子一樣。但是,我們使用的是SendResutlsStart()方法來傳輸資料。 SendResultsRow()方法也是傳送一個SqlDataRecord物件到客戶端,但是我們可以多次呼叫它,從而做到傳送多條記錄。最後,呼叫SendResultsEnd()方法用來標記已經完成資料傳輸操作。

我們已經開發完了儲存過程。現在就可以將這個專案編譯為一個程式集(.DLL)。但是我們的工作並沒有到此結束。我們還需要部署這個程式集和儲存過程到SQL Server資料庫。有兩種方法可以完成這個工作手動和自動。手動方法是使用T-SQL語句註冊你的程式集,並將儲存過程部署到SQL Server資料庫中。在本例中,我將使用自動的方法來部署儲存過程到SQL Server資料庫。

右鍵單擊你的專案,然後在選單中選擇部署選項。


如此就會自動地完成註冊程式集和部署儲存過程的工作。注意,只有在你建立專案時添加了資料庫引用的時候,才會出現部署選項。如果因為某些原因你沒能新增資料庫引用,那麼你可以通過專案屬性對話方塊來設定它。


如果你在SQL Server Management Studio檢視Northwind資料庫的話,那麼就應該可以看到和下圖相似的結果。


注意,在儲存過程節點下出現了我們建立的所有方法(有圖示的),並且在程式集節點下出現了我們的程式集。

就是這些東西,很簡單吧。現在你就可以在你的程式中呼叫這些儲存過程了。你也可以在SQL Server Management Studio中來測試它們。

作者簡介:Bipin JoshiDotNetBips.com的管理員。他是的發起人,這個公司提供.NET framwork的培訓和諮詢服務。他在印度孟買為開發者提供培訓。他也是微軟的MVP(ASP.Net)ASPInsiders的會員。

相關推薦

Spring原始碼解析--《SPRING技術內幕:深入解析Spring架構設計原理》讀書筆記IOC容器初始化過程

通過閱讀相關章節內容,Spring中IOC容器的載入中,我們需要了解下列幾個概念: Resource:是一個定位、訪問資源的抽象介面,包含了多種資源操作的基礎方法定義,如getInputStream()、exists()、isOpen()、getD

以太坊連載C++客戶端的安裝定製

從源安裝客戶端 概覽 cpp-ethereum 程式碼庫在幾個Git庫中傳播,庫在Git上被分組為webthree-umbrella庫下的子模組。 我們用一般的CMake編譯系統來生成平臺特定的架構檔案,這意味著工作流程和你用的任何作業系統都非常類似: 安裝編譯

luaCC呼叫lua

      lua和c有兩種關係:       一種是在lua中呼叫C的函式,C稱為庫程式碼,一種是C中呼叫lua,C就稱為應用程式程式碼,此時C中包含了lua的直譯器    C程式碼部分        注意在C++中,通常要把lua的一些標頭檔案定義在extern “c”

SQL奇技淫巧01給查出的資料排序編個號【row_number() over(order by c)】mysql,db2,oracle,sqlserver通用

我們天天都在跟資料庫打交道,寫下的程式碼不計其數,寫下的SQL更是可以繞地球幾圈。這裡收集關於SQL的神奇語法及用法,雖然你可能沒有用過,但這些SQL卻可以在關鍵的時候,派上用場。 我對SQL語句的理解,可以比作一座橋樑,將零散的資料組合起來,拿到我所需要的有效資訊。也以此記錄一下使用心得 一. 語法

C++傳智筆記5C++完整demo

內部 urn else clas spa char log getx system MyPoint.h #pragma once class MyPoint { private: double x0, y0; //點坐標 public: void setPoint(d

TF-IDF余弦相似性的應用自動摘要

下一步 dip target 似的 abs tps .net ebo ace 轉:http://www.ruanyifeng.com/blog/2013/03/automatic_summarization.html 有時候,很簡單的數學方法,就可以完成很復雜的任務。 這個

C語言C語言概述

感覺 用途 計算機 一行 可用 讓其 pan 復合語句 sso 學習筆記:  運算符  函數 一個簡單的C語言程序 整型變量 換行符 註釋 關鍵字 概述:C語言程序是什麽樣

Exchange 2016國內版O365混合部署4配置Exchange 公網證書

導入 mtp targe 新建 lan 創建 image AD alt Exchange混合部署需要安裝一個第三方權威機構頒發的公網證書,用於郵件流的安全傳輸,詳細的步驟technet也有寫: https://technet.microsoft.com/zh-cn/l

Exchange 2016國內版O365混合部署6混合後的操作和驗證

分享圖片 In 報告 mailbox inf 通訊錄 png 完成後 動手 雲端和本地統一的通訊錄: AAD Connect 目錄同步後,登錄O365管理員界面查看用戶,可以看到本地的兩個用戶已經同步上來了,同步類型顯示已與AD同步。 登錄一個雲端用戶的郵箱,在收件人處輸

強化學習馬爾可夫決策過程

最優 最大值 公式 des 版本 ams 強化學習 有獎 RoCE Finite Markov Decision Process 馬爾可夫決策過程(MDP)是對連續決策進行建模,當前的動作不僅對當前產生影響,而且還會對將來的的情況產生影響,如果從獎勵的角度,即MDP不僅影響

數值分析C++實現線性方程組的高斯-賽德爾迭代法

線性方程組的直接解法之後,就輪到迭代解法了,直接解法針對的是低階稠密矩陣,資料量較少,而工程上有更多的是高階係數矩陣,使用迭代法效率更高,佔用的空間較小。 迭代法的最基本思想就是由初始條件,比如說初始解向量隨便列舉一個,就0向量也行,然後進行迭代,k到k+1,一步一步從k=1開始去逼近真實解

數值分析C++實現三對角線方程組的追趕法

這次來實現三對角線方程組的追趕法,追趕法的本質還是高斯消元法,而且是沒選主元的高斯消元法,只是因為Ax=b中係數矩陣A非常特殊,所以就可以採用相對特殊的方法來解方程組。同樣,按照常規的步驟,先分析什麼是追趕法,再給出追趕法的數學步驟,最後用C++實現這種演算法。 (一)追趕法的功能和步驟 明

Windows Service 學習系列C# windows服務安裝、解除安裝、啟動和停止Windows Service

一、通過CMD安裝、解除安裝、啟動、停止Windows Service     方法一   1.以管理員身份執行cmd   2.安裝windows服務       切換cd C:\Windows\Microsoft.NET\Framework\v4.0.30319(InstallUtil.e

SQL入門經典》筆記第一章歡迎進入SQL世界

想刷刷書,順便做個筆記~ 下列內容大部分都是直接抄書,侵刪 1. 什麼是ANSI SQL? “美國國家標準化組織(ANSI)是一個核準多種行業標準的組織”。1987年,ISO吧ANSI SQL作為國標標準,目前最新的標準是SQL-2008。   2. SQL-2008:

Sql時間日期查詢-SQL查詢今天、昨天、7天內、30天

今天的所有資料:select * from 表名 where DateDiff(dd,datetime型別欄位,getdate())=0 昨天的所有資料:select * from 表名 where DateDiff(dd,datetime型別欄位,getdate())=1

Phoenix3Phoenix執行sql指令碼

一、實現功能 將需要執行sql語句寫入指令碼,然後,使用psql.py執行。 二、步驟 1.指令碼內容 (1)us_population.sql CREATE TABLE IF NOT EXISTS us_population ( "state" CHAR(2) NOT NULL

Elasticsearch通關教程如何通過SQL查詢Elasticsearch

  這篇博文字來是想放在全系列的大概第五、六篇的時候再講的,畢竟查詢是在索引建立、索引文件資料生成和一些基本概念介紹完之後才需要的。當前面的一些知識概念全都講解完之後再講解查詢是最好的,但是最近公司專案忙經常加班,畢竟年底了。但是不寫的話我怕會越拖越久,最後會不了了之了,所以剛好上海週末下雪,天冷無法出門,就

程式設計規範C/C++的命名原則

無以規矩,不成方圓。 符合規範的統一命名是程式編寫的基本規矩之一。很多時候我們不願意接手別人的程式碼,原因之一就是程式碼命名很亂;我們自己寫程式碼時經常寫到後面忘了前面,也有可能是我們沒有養成規範的命名習慣。當寫程式碼成為一種藝術的美時,這種美的最直接的體現就

win10 cuda_小白之旅1c語言的回顧

博主自己學習,僅此記錄,並方便學過c、已經配置好cuda的朋友交流學習。(我機子cuda9.0) 第一個cuda專案         我用的ide是vs2015。新建專案:選中cuda。 然後會自動生成一個.cu,求和的一個程式,用來檢查你是否安裝好,沒啥實際意思(

David Silver強化學習公開課馬爾科夫決策過程

在強化學習中,馬爾科夫決策過程(Markov decision process, MDP)是對完全可觀測的環境進行描述的,也就是說觀測到的狀態內容完整地決定了決策的需要的特徵。幾乎所有的強化學習問題都可以轉化為MDP。本講是理解強化學習問題的理論基礎。 馬爾科夫過程 M