.Net新手☞数据库操作
在線對象:
Connection 用來和數據庫建立連接
Command??? 表示執行的數據操作命令
Parameter? 表示數據操作命令中的參數
DataReader 用來以只讀只進方式讀取數據
Transaction用來實現事務
DataAdapter用來為數據容器加載數據和把更新后的數據傳回數據庫
離線對象:
DataSet??? 數據容器,就好像一個數據庫,容納多個DataTable和關系
DataTable? 數據容器,就好像一個數據表,又DataRow和DataColunn構成
DataRow??? 代表DataTable中的一行記錄
DataColumn 代表DataTable的列,就好像字段
DataView?? 和數據庫的視圖差不多,用來為一個DataTable建立多種視圖
DataRelation 表示各個DataTable之間的關系,并提供瀏覽父表記錄和子表記錄的方式
Constraint 表示DataTable的主鍵約束和外鍵約束
一、使用Connection對象連接數據庫
? string sConnectionString="";
? sConnectionString=string.Format("Sever=.;Database=數據庫名;User ID=sa;Password=sa";Connection TimeOut=2);//可信任連接Trusted_Connection=True
? Sqlconnection conn=new Sqlconnection(sConnectionString);
? try
? {
??? conn.Open();
??? if(conn.State==ConnectionState.Open)
??? Response.Write("數據庫連接成功");
? }
? catch(SqlException sqlException)
? {
??? Response.Write(sqlException.Message);
? }
? finally
? {
??? if(conn.State==ConnectionState.Open)
??? conn.Close();
? }
從Web.config中獲取字符串連接:ConfigurtionManager.ConnectionString["con"].ToString
二、枚舉所有可用數據源
protected void Page_Load(object sender, EventArgs e)
{
? if(!IsPostBack)
? {
???? SqlDataSourceEnumerator instance = SqlDataSourceEnumerator.Instance;
???? ddl_Server.DataSource = instance.GetDataSource();
???? ddl_Server.DataTextFiled = "ServerName";
???? ddl_Server.DataBind();
? }
}
注意:列舉當前網絡中可用的SQL Server服務器示例是個非常慢的操作,請謹慎用。
三、使用SqlCommand執行SQL語句
在使用在線對象時,要盡量早關閉活動連接。我們使用using{}語句來自動釋放活動連接。
代碼如下:
using (Sqlconnection conn=new Sqlconnection(sConnectionString))
{
conn.open()
?using(Sqlcommand cmd=new Sqlcommand(sSql,conn))
?{
?? cmd.ExecuteNonQuery();
?}
}
使用了using以后,Connection對象不再需要Close(),using語句會在代碼結束時自動調用相應對象的Dispose()方法來釋放對象資源。
SqlCommand對象的主要方法為:
ExecuteNonQuery()?? 執行SQL語句并返回所影響的行,常用于執行一個不返回任何結果的操作。比如插入等
ExevuteReader()???? 執行查詢語句并返回SqlDataReader,常用于返回記錄集的操作。比如查詢
ExecuteScalar()???? 執行查詢并返回結果的第一行第一列,常用于返回一個值的操作。比如Select count(*) from tbClass
SQL注入帶來的威脅
在SQL語句中要求對字符型數據使用單引號來包圍,而對于數字型數據又不需要。如果我們不檢測輸入的數字型參數是否真正是數字,或者不檢測輸入的字符型參數中是否包含單引號,則很有可能產生漏洞,遭到著名的“SQL注入攻擊”。
SQL語句用到的SQL兩個技術:
1、SQL語句可以多個一起執行,用分號隔開
2、“--”會注釋掉后面的語句,因此“'”就會被忽略,不會引發單引號不匹配的錯誤。
使用參數防止SQL注入
protected void btn_SeachClass_Click(0bject sender,EventArgs e)
{
? string sConnectionString=@"server=.;database=Forum;Trusted_Connection=True";
? using(SqlConnection conn=new SqlConnection(sConnectionString))
? {
??? conn.Open();
??? using(SqlCommand cmd=new SqlCommand("select count(*) from tbClass where ClassName=@ClassName",conn))
??? {
?????? cmd.Parameters.Add("@ClassName",SqlDbType.Varchar,50);
?????? cmd.Parameters["@ClassName"].Value=tb_ClassName.Text;
?????? Response.Write(string.Format("共有{0}條記錄符合要求<br>",cmd.ExecuteScalar().ToString()));
??? }
? }
}
注意:
SQL語句或者存儲過程中指定的所有參數必須和Parameters屬性中所有參數對應。
參數集合的Add()方法有多種重載,還有一個AddWithValue()方法可以同時為參數賦值。cmd.Parameters.AddWithValue("@ClassName",tb_ClassName.Text)
存儲過程:
SqlParameter對象有個Direction方法。對于SQL語句中的參數,這個值沒有什么意義,它是用來指定存儲過程參數的方向。它的值由ParameterDirection枚舉來定義的,共有以下4個類型:
Input
InputOutput
Output
ReturnValue
存儲過程模板:
CREATE PROCEDURE db.StoredProcedure1
/*
(
@parameter1 int =5,
@parameter2 datatype output
)
*/
AS
/*SET NOCOUNT ON */
RETURN
例子:
CREATE PROCEDURE db.StoredProcedure1
(
@ClassName varchar(50),????????????? //輸入參數
@BoardName varchar(50),????????????? //輸入參數
@ClassID?? varchar(50) output??????? //輸出參數
)
AS
declare @BoardCount int;
Set @ClassID=(Select ClassID from tbClass where ClassName=@ClassName);
Insert into tbBoard(BoardName,BoardClassID)vaules(@BoardName,@ClassID);
Set @BoardCount = (Select count(*) from tbBoard);
RETURN @BoardCount;
使用SqlCommand對象執行存儲過程
protected void btn_AddBoard_Click(object sender ,EventArgs e)
{
?? string sConnectionString = @"sever=(local);database=Forum;Trusted_Connection=True";
?? using(Sqlconnection conn=new Sqlconnection(sConnectionString))
?? {
???? conn.open();
???? using(Sqlcommand com=new Sqlcommand ("CreateBoard",conn))?? //CreateBoard是存儲過程名字
???? {
?????? cmd.CommandType=Command.Type.StoredProcedure;
?????? cmd.Parameters.Add("@ClassName",SqlDbType.Varchar,50);
?????? cmd.Parameters["@ClassName"].Value=tbClassName.Text;
?????? cmd.Parameters["@ClassName"].Direction=ParameterDirection.Input;
?????? cmd.Parameters.Add("@BoardName",SqlDbType.Varchar,50);
?????? cmd.Parameters["@BoardName"].Value=tbBoardName.Text;
?????? cmd.Parameters["@BoardName"].Direction=ParameterDirection.Input;
?????? cmd.Parameters.Add("@ClassID",SqlDbType.Varchar,50);
?????? cmd.Parameters["ClassID"].Direction=ParameterDirection.Output;
?????? cmd.Parameters.Add("@BoardCount",SqlDbType.Int);
?????? cmd.Parameters["@BoardCount"].Direction=ParameterDirection.ReternValue;
?????? cmd.ExecuteNonQuery();
?????? foreach(SqlParameter parameter in cmd.Parameters)
?????? {
????????? Response.Write(string.Format("參數名:{0},參數方向:{1},參數值:{2}<br>",parameter.ParameterName,parameter.Direction.ToString(),parameter.Value));
?????? }
???? }
?? }
}
注意以下幾點:
1、CommandType枚舉。用來枚舉所有的命令類型,默認是CommandType.Text,用于執行SQL語句。如果把SqlCommand的CommandText設置為一個存儲過程名,就指定CommandType為CommandType.StoredProcedure。
2、Parameter集合。我們需要把所有存儲過程需要的參數都添加到Sqlcommand的SqlParameterCollection集合中去,參數名、參數類型和參數大小都應該和存儲過程中聲明的參數對應。參數的方向用ParameterDirection枚舉來定義。
存儲過程與事務:
Create procedure Transfer
as
begin tran
/*內容*/
commit tran
return
在存儲過程中聲明變量的方法是:declare @變量名 數據類型(example: int vachar? and so on)
使用DataReader訪問數據
一、讀取單記錄集
string sConnection = @"server=(local);database=Forum;Trusted_Connection=True";
using (SqlConnection conn=new SqlConnection(sConnection))
{
?? conn.Open();
?? using (SqlCommand cmd=new SqlCommand("select * from tbBoard",conn))
?? {
???? using (SqlDataReader dr=cmd.ExecuteReader())
???? {
??????? if(dr.HasRows)//記錄集是否為空
??????? {
????????? System.Text.StringBuilder htmlStr=new System.Text.StringBuilder();//使用StringBuilder構造字符串的效率高
????????? for(int i=0;i<=dr.FieldCount;i++)
????????? {
??????????? htmlStr.Append(string.Format("{0}",dr.GetName(i)));
????????? }
????????? while(dr.Read())
????????? {
??????????? for(int i=0;i<dr.FieldCount;i++)
??????????? {
?????????????? htmlStr.Apend(string.Format("{0}",dr.GetValues(i)));//構造記錄行
??????????? }??
???????????
????????? }
????????? Response.Write(htmlStr);
??????? }
???? }
?? }
}
注意的問題:
1、DataReader對象是不能用New關鍵字來實例化的,可以通過Command對象的ExecuteReader()方法獲得一個DataReader對象。
2、DataReader是一行一行向前讀取記錄的,因此,我們常使用while(dr.Read())來遍歷所有行。Read()方法能使DataReader讀取一條記錄,并前進到下一條記錄,如果已經到達了記錄的底部則返回false。
3、DataRead對象的一些屬性如下:
? FieldCount?? 獲取當前行的列數。我們的程序需要遍歷所有列,可以使用這個屬性獲得列數。
? HasRows????? 指示DataReader是否包含一行或多行。在讀取記錄集內容以前常用這個屬性來判斷記錄集是否有記錄。
4、DataRead對象的一些重要方法如下:
? GetInt16()、GetString()、GetDataTime()等GetXXX()方法(其中XXX代表.NET的一種類型)。使用這些方法可以讀取行中某列的值,并直接以相應的.NET類型返回。
? GetValue()和GetName().? 使用GetValue()方法可以讀取行中某列的值,它和上面的GetXXX()差不多,只不過返回object類型的值。GetName()則返回行中某列的列名。
二、讀取多記錄集
DataReader支持多記錄集的讀取,可以使用NextResult()方法移動到下一個記錄集。
1、DataReader的構造方法還可以接受CommandBehavior枚舉作為參數,我們可以使用CommandBehavior.CloseConnection,使得DataReader關聯的Connection對象在記錄集讀取完畢后立即被關閉,且比using代碼塊要快。
2、在真正讀取某行某列值以前應該使用DataReader的IsDBNull(列索引號)方法來判斷某列是否有值,以免因為不能進行類型轉換導致異常。
string sConnection = @"server=(local);database=Forum;Trusted_Connection=True";
using (SqlConnection conn=new SqlConnection(sConnection))
{
?? conn.Open();
?? using (SqlCommand cmd=new SqlCommand("select * from tbBoard",conn))
?? {
???? using (SqlDataReader dr=cmd.ExecuteReader(CommandBehavior.CloseConnection)
???? {
??????? if(dr.HasRows)//記錄集是否為空
??????? {
????????? do
????????? {
?????????? System.Text.StringBuilder htmlStr=new System.Text.StringBuilder();//使用StringBuilder構造字符串的效率高
?????????? for(int i=0;i<=dr.FieldCount;i++)
?????????? {
???????????? htmlStr.Append(string.Format("{0}",dr.GetName(i)));
?????????? }
?????????? while(dr.Read())
?????????? {
???????????? for(int i=0;i<dr.FieldCount;i++)
???????????? {
??????????????? htmlStr.Apend(string.Format("{0}",dr.GetValues(i)));//構造記錄行
???????????? }??
???????????
?????????? }
?????????? Response.Write(htmlStr);
?????????
????????? }while(dr.NextResult())??
??????? }
???? }
?? }
}
DataSet數據容器
一、創建DataSet
我們建立數據庫中tbClass表和tbBoard表的本地副本
//先建立數據庫
DataSet Forum=new DataSet("Forum");
//再來建立兩個數據表
DataTable tbClass=new DataTable("tbClass");
DataTable tbBoard=new DataTable("tbBorad");
//把兩個表加入數據庫
Forum.Tables.Add(tbClass);
Forum.Tables.Add(tbBorad);
//建立tbClass的兩列
DataColumn ClassID=new DataColumn("ClassID",typeof(System.String));
DataColumn ClassName=new DataColumn("ClassName",typeof(System.String));
//設定ClassID不為空
ClassID.AllowDBNull=false;
//把列加入到tbClass表
tbClass.Columns.Add(ClassID);
tbClass.Columns.Add(ClassName);
//設定tbClass表的主鍵
tbClass.PrimaryKey=new DataColumn[]{ClassID};
//建立tbBoard的三列
DataColumn BoardID=new DataColumn("BoardID",typeof(System.String));
DataColumn BoardName=new DataColumn("BoardName",typeof(System.String));
DataColumn BoardClassID=new DataColumn("BoardClassID",typeof(System.String));
//設定BoardID不為空
BoardID.AllowDBNull=false;
//把列加入到tbBoardID表
tbBoard.Columns.Add(BoardID);
tbBoard.Columns.Add(BoardName);
tbBoard.Columns.Add(BoardClassID);
//設定tbBoard表的主鍵
tbBoard.PrimaryKey=new DataColumn[]{BoardID};
說明:
1、在建立了DataTable后別忘了把它加入到DataSet;同樣,在建立DataColumn后別忘了加入到DataTable中。
2、對于DataTable的PrimayKey屬性,它需要賦值一個DataColumn的數組。這是因為一個表可能有幾個主鍵組成聯合主鍵,對于單主鍵的表,數組只有一個成員。
? 然后是構建數據庫
//為兩個表各加入5條記錄
for(int i=0;1<=5;i++)
{
? //實例化tbClass表的行
? DataRow tbClassRow=tbClass.NewRow();
tbClassRow["ClassID"]=Guid.NewGuid();
tbClassRow["ClassName"]=string.Format("分類{0}",i);
//把行加入到tbClass表
tbClass.Rows.Add(tbClassRow);
//實例化tbBoard表的行
DataRow = tbBoard.NewRow();
tbBoardRow["BoardID"]=Guid.NewGuid();
tbBoardRow["BoardName"]=string.Format("版塊{0}",i);
tbBoardRow["BoardClassID"]=tbClassRow["ClassID"];
//把行加入tbBoard表
tbBoard.Rows.Add(tbBoardRow);
}
二、訪問DataSet
1、假設我們有一個DataTable dt,可以使用dt.Rows[行索引號][列索引號]得到某行某列的值。比如我們要得到dt三行二列的數據,就使用dt[2][1].
2、我們有兩種遍歷集合的方法:使用foreach和for;對于后者,我們需要知道集合的Item總數,可以使用集合的Count屬性。如果遍歷需要有序,我們只能使用for進行。
三、使用DataRelation實現父子表
DataSet.Relations.Add("關聯名稱", 父關聯主鍵字段, 子關聯外來鍵字段)
??????? // 構建父子關系
??????? Forum.Relations.Add("RelationBetweenClassAndBoard", ClassID, BoardClassID);
??????? // 從關系獲取父表
??????? DataTable dtParent = Forum.Relations["RelationBetweenClassAndBoard"].ParentTable;
??????? // 從關系獲取子表
??????? DataTable dtChild = Forum.Relations["RelationBetweenClassAndBoard"].ChildTable;
??????? // 構建輸出字符串
??????? System.Text.StringBuilder htmlStr = new System.Text.StringBuilder();
??????? // 表開始
??????? htmlStr.Append("<table border='1' cellPadding='5' cellSpacing='0' style='font-size:9pt;font:宋體'>");
??????? // 遍歷父表中所有行
??????? for (int i = 0; i < dtParent.Rows.Count; i++)
??????? {
??????????? // 父表數據行開始
??????????? htmlStr.Append("<tr? style='background-color=#f0f0f0'>");
??????????? // 遍歷父表行中列
??????????? for (int j = 0; j < dtParent.Columns.Count; j++)
??????????? {
??????????????? if (!dtParent.Rows[i].IsNull(j))
??????????????????? htmlStr.Append(string.Format("<td>{0}</td>", dtParent.Rows[i][j]));
??????????? }
??????????? // 父表數據行結束
??????????? htmlStr.Append("</tr>");
??????????? // 遍歷子表中所有行
??????????? for (int j = 0; j < dtParent.Rows[i].GetChildRows("RelationBetweenClassAndBoard").Length; j++)
??????????? {
??????????????? // 子表數據行開始
??????????????? htmlStr.Append("<tr>");
??????????????? // 遍歷子表行中列
??????????????? for (int k = 0; k < dtParent.Columns.Count; k++)
??????????????? {
??????????????????? if (!dtParent.Rows[i].GetChildRows("RelationBetweenClassAndBoard")[j].IsNull(k))
??????????????????????? htmlStr.Append(string.Format("<td>{0}</td>", dtParent.Rows[i].GetChildRows("RelationBetweenClassAndBoard")[j][k]));
??????????????? }
??????????????? // 子表數據行結束
??????????????? htmlStr.Append("</tr>");
??????????? }
??????? }
??????? // 表結束
??????? htmlStr.Append("</table><br>");
??????? Response.Write(htmlStr);
使用DataAdapter來獲取數據
使用DataTableMapping類來對DataTable和DataColumn進行友好名稱映射
DataTableMapping dtmClass=da.TableMappings.Add("Table","論壇分類表");
dtmClass.ColumnMappings.Add("ClassID","分類ID");
dtmClass.ColumnMappings.Add("ClassName","分類名");
DataTableMapping dtmBoard=da.TableMappings.Add("Table","論壇版塊表");
dtmBoard.ColumnMappings.Add("BoardID","版塊ID");
dtmBoard.ColumnMappings.Add("BoardName","版塊名");
dtmBoard.ColumnMappings.Add("BoardClassID","所屬分類ID");
更多連接字符串的格式可以去http://www.connectionstrings.com/ 去查詢
轉載于:https://www.cnblogs.com/Mygirl/archive/2011/06/30/2094831.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的.Net新手☞数据库操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: KlayGE中的FXAA已经完成
- 下一篇: WPF 自定义模板