-
ADO.NET
程序要和數據庫交互要通過ADO.NET進行,通過ADO.Net就能在程序中執行SQL了。
ADO.Net中提供了對各種不同的數據庫的統一操作接口。
-
連接字符串:
程序通過連接字符串指定要連接那台服務器上的那個實例的數據庫、用什么用戶密碼。
-
項目內嵌mdf文件形式的連接字符串如下:
Data Source=.\SQLEXPRESS;AttachDBFilename=|DataDirectory|\ Database1.mdf;Integrated Security=True;User Instance=True
".\SQLEXPRESS"表示"本機上的SQLEXPRESS實例",如果數據庫實例名不是SQLEXPRESS,則需要修改。"Database1.mdf"為mdf文件名。
項目連接外部Mdf文件形式的連接字符串如下:
Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321
".\MSSQL"表示"本機上的MSSQL實例",其中的"Ado.net"是數據庫名稱。
- ADO.Net中通過SqlConnection類創建到SQLServer的連接,SqlConnection代表一個數據庫連接,ADO.Net中的連接等資源都實現了IDisposable接口,可以使用using進行資源管理。
利用using可以進行資源的釋放。
也可以使用try catch.
例如:
Try
{}
Catch
{}
Finally
{
Conn.Colse();
Conn.Dispose();
}
-
連接數據庫主要分為一下步驟:
- 創建連接字符串;
例如:string conn=" Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321"
- 創建Connection對象;
SqlConnection conn=new SqlConnection(conn) 注意:這里要引入命名空間:usingSystem.Data.SqlClient;
-
打開數據庫連接;
Conn.Open();
注意:這里的連接字符串在這里也可以找到:服務器資源管理器-》右鍵點擊連接好的數據庫-》在屬性中找到連接字符串-》然后復制粘切就可以了!
-
ASO.NET提供了兩個組件可以使程序訪問和處理數據:
1》.NET Framework數據提供程序;
.NET Framework數據提供程序是專門為數據處理,以及快速的只進、只讀訪問數據而設計的組件。使用該組件,可以聯接到數據庫、執行命令和檢索結果,直接對數據庫進行操作等!
2》DataSet(數據集);
DataSet是專門為獨立於任何數據源的數據訪問而設計的。使用Dataset,可以不必直接和數據庫打交道,可以大批量的操作數據。也可以將數據綁定到控件中。
-
可能遇到的錯誤:
"由於啟動用戶實例的進程時出錯,導致無法生成SQL Server的用戶實例"
-
在程序中執行簡單的Insert語句(插入語句)
using ( SqlCommand cmd=conn.CreateCommand()) 要想向程序發出一條命令,就必須創建一個SqlCommand對象!
{
cmd.CommandText = "Insert into MyTable(Name) values('abc')"; 命令文本。
cmd.ExecuteNonQuery(); 執行一個非查詢語句!這樣就將上面的命令文本就執行了!
Console.WriteLine("插入成功!");
}
注意:這里的表名不能為Table,要將其改為其他名稱!然后就是必須將下列語句放入到Main方法里面!
string dataDir = AppDomain.CurrentDomain.BaseDirectory;
if (dataDir.EndsWith(@"\bin\Debug\")
|| dataDir.EndsWith(@"\bin\Release\"))
{
dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;
AppDomain.CurrentDomain.SetData("DataDirectory", dataDir);
}
具體解釋參考:
-
簡單的用戶登錄:
Console.WriteLine("請輸入用戶名?");
stringusername=Console.ReadLine();
Console.WriteLine("請輸入密碼?");
stringpassword=Console.ReadLine();
using (
SqlConnectionconn=
newSqlConnection(
@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321")
)
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select * from T_User where Name='"+username+"'";
using (SqlDataReaderreader=cmd.ExecuteReader())
{
if(reader.Read())
{
stringdbpassword=reader.GetString(reader.GetOrdinal("password"));
if(password==dbpassword)
{
Console.WriteLine("登陸成功!");
}
else
{
Console.WriteLine("密碼錯誤,登錄失敗!");
}
}
else
{
Console.WriteLine("用戶名錯誤!");
}
}
}
}
注意:對於上述表(T_User)中的關鍵字中的用戶名和密碼都應該為nvarchar(50)類型的,如果為默認的nchar(10),即使你輸入的用戶名和密碼正確,也登陸不成功!在這里強調一點是,我在數據庫中的密碼都是6位的!因此是登錄不成功的!如果是10位數的話,就可以登陸成功。那么為什么呢?
原因是:默認的nchar(10)的字符串長度為10,要是用戶輸入的字符串不夠10的話,就會自動加空格!所以要想讓用戶登陸成功,還必須在后面添加4個空格。因此,一般我們將用戶名和密碼的類型設置為nvarchar(50)類型!
- 接受用戶輸入的用戶名和密碼,然后將用戶輸入的數據插入的對應的表中!
Console.WriteLine("請輸入用戶名?");
stringusername=Console.ReadLine();
Console.WriteLine("請輸入密碼?");
stringpassword=Console.ReadLine();
using (
SqlConnectionconn=
newSqlConnection(
@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321")
)
{
conn.Open();
Console.WriteLine("數據庫打開成功!");
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="insert into T_User(Name,Password) values('"+username+"','"+password+"')";
cmd.ExecuteNonQuery();
Console.WriteLine("插入成功!");
}
}
有時我們不注意,會將表的名稱設置為關鍵字例如:Table、User等,要想使用這些,可以給它們加括號例如:[Table]、[User]
一般情況下盡量不要以關鍵字作為表的名稱,而應該避免。例如:可以用T_開頭的命名!字段是以F開頭!
-
ExecuteScalar的使用:
using ( SqlConnectionconn=newSqlConnection(@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321"))
{
conn.Open();
Console.WriteLine("打開數據庫成功!");
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select count(*) from T_User";
//cmd.ExecuteScalar()的意思是顯示查詢結果中,第一行第一列的數據!
Console.WriteLine(cmd.ExecuteScalar());
}
}
注意:ExecuteScalar()返回值類型是Object類型!因為第一行第一列任何數據都是有可能的!
-
不光select可以使用ExecuteScalar,insert也可以!
例如:一般的SQL插入語句為:
Insert into T_User(Name,Password) values('liming','456654')
只要在values的全面加上"output inserted.【主鍵名】",意思是輸出剛剛插入的主鍵;
using (
SqlConnectionconn=
newSqlConnection(
@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321")
)
{
conn.Open();
using ( SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="insert into T_User(Name,Password) output inserted.Id values('xiaowang','789987')";
intid=Convert.ToInt32(cmd.ExecuteScalar());
Console.WriteLine("新插入的主鍵為{0}",id);
}
}
-
將查詢后的數據輸出:
using ( SqlConnectionconn=newSqlConnection(@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321"))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select * from T_User";
using (SqlDataReaderreader=cmd.ExecuteReader()) //這里的reader是一個數據集類型!
{
while (reader.Read()) //每循環一次就會往下移一行。
{
//下列其中的reader.GetOrdinal("Name")的意思是得到查詢語句中"Name"所在的列序號!
Console.WriteLine(reader.GetString(reader.GetOrdinal("Name")));
}
}
}
}
上面程序是得到單列數據!也可以得到多行數據!例如:
using (
SqlConnectionconn=
newSqlConnection(
@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321")
)
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select * from T_User";
using (SqlDataReaderreader=cmd.ExecuteReader())
{
while (reader.Read())
{
intid=reader.GetInt32(reader.GetOrdinal("Id"));
stringusername=reader.GetString(reader.GetOrdinal("Name"));
stringpassword=reader.GetString(reader.GetOrdinal("Password"));
Console.WriteLine("Id={0}\tName={1}\tPassword={2}", id, username, password);
}
}
}
Reader的GetString方法是得到該列的字符串!
另外還有GetInt32方法是得到該列的數據!
-
Close和dispose的區別:
Close();關閉之后還能打開,而dispose關閉之后就打不開了!
如果不使用using而使用close方法之后就必須調用dispose方法!
Using出了作用域以后調用dispose,SqlConnection、FileStream等的dispose內部都會做這樣的判斷:判斷有沒有close ,如果沒有就先執行close在執行dispose!也就是說可以不寫close直接dispose也是可以的!但一定不能沒有dispose!
-
學了ExecuteScalar之后,我們就可以寫登陸界面!
Console.WriteLine("請輸入用戶名?");
stringusername=Console.ReadLine();
Console.WriteLine("請輸入密碼?");
stringpassword=Console.ReadLine();
using (SqlConnectionconn=newSqlConnection(@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321"))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select count(*) from T_User where Name='"+username+"'and Password='"+password+"'";
inti=Convert.ToInt32(cmd.ExecuteScalar());
if (i>0)
{
Console.WriteLine("登陸成功!");
}
else
{
Console.WriteLine("用戶名或密碼錯誤!");
}
}
}
基本思想就是通過條件限制查詢表中是否有符合條件的數據,如果有那么就證明登陸成功了!
在這里要注意:我輸入正確的用戶名,密碼輸入1' or '1' = '1 也可以登陸成功!
因此我們需要解決這個問題:即將上面程序更改為下面代碼!
Console.WriteLine("請輸入用戶名?");
stringusername=Console.ReadLine();
Console.WriteLine("請輸入密碼?");
stringpassword=Console.ReadLine();
using (SqlConnectionconn=newSqlConnection(@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321"))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select count(*) from T_User where Name=@Nm and Password=@Pw";
cmd.Parameters.Add(newSqlParameter("Nm", username));
cmd.Parameters.Add(newSqlParameter("Pw", password)); //這樣程序會直接將用戶輸入的字符串和數據庫中的數據進行比較!而不再是添加字符的形式添加到SQL語句中!
inti=Convert.ToInt32(cmd.ExecuteScalar());
if (i>0)
{
Console.WriteLine("登陸成功!");
}
else
{
Console.WriteLine("用戶名或密碼錯誤!");
}
}
}
-
Windows窗體登錄程序實現過程:
private void IncErroTimes()
{
using (SqlConnection conn = new SqlConnection(@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321"))
{
conn.Open();
using (SqlCommand updatecmd = conn.CreateCommand())
{
updatecmd.CommandText = "update T_User set Errortimes=Errortimes+1 where Name=@Nm";
updatecmd.Parameters.Add(new SqlParameter("Nm", txtUserName.Text));
updatecmd.ExecuteNonQuery(); 執行的是一個非查詢語句!
}
}
}
//當登錄成功是將登陸次數歸零!
private void ResetErroTimes()
{
using (SqlConnection conn = new SqlConnection(@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321"))
{
conn.Open();
using (SqlCommand updatecmd = conn.CreateCommand())
{
updatecmd.CommandText = "update T_User set Errortimes=0 where Name=@Nm";
updatecmd.Parameters.Add(new SqlParameter("Nm", txtUserName.Text));
updatecmd.ExecuteNonQuery();
}
}
}
private void button1_Click(object sender, EventArgs e)
{
using (
SqlConnection conn =
new SqlConnection(
@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321")
)
{
conn.Open();
using (SqlCommand cmd=conn.CreateCommand())
{
cmd.CommandText = "select * from T_User where Name=@Nm";
cmd.Parameters.Add(new SqlParameter("Nm", txtUserName.Text));
using (SqlDataReader reader=cmd.ExecuteReader())
{
if (reader.Read())
{
int errotimes = reader.GetInt32(reader.GetOrdinal("Errortimes"));
if (errotimes > 2) /從零開始!
{
MessageBox.Show("登錄次數錯誤過多,禁止登陸!");
return;
}
string dbpassword = reader.GetString(reader.GetOrdinal("Password"));
if (dbpassword==txtPassword.Text)
{
MessageBox.Show("登陸成功!");
ResetErroTimes();
}
else
{
IncErroTimes(); //由於以下問題,因此使用調用函數。
//在同一個連接中,如果SqlDataReader沒有關閉,則是不能進行update等語句的!也就是不能對數據庫進行改動!這是我們可以重新建立一個連接,將其放入到一個函數里面,然后調用這個函數|!
/* using (SqlCommand updatecmd = conn.CreateCommand())
{
updatecmd.CommandText = "update T_User set Errortimes=Errortimes+1 where Name=@Nm";
updatecmd.Parameters.Add(new SqlParameter("Nm", txtUserName.Text));
updatecmd.ExecuteNonQuery();
}*/
MessageBox.Show("密碼錯誤,登錄失敗!");
}
}
else
{
MessageBox.Show("用戶名不正確");
}
}
cmd.ExecuteReader();
}
}
}
-
將數據插入到表中:
if (odfImport.ShowDialog()==DialogResult.OK) //其中odfImport是OpenFileDialog控件的名稱!確認用戶選擇的是"確定"按鈕!
{
using (FileStream fileStream = File.OpenRead(odfImport.FileName))//打開文件
{
using (StreamReader streamReader=new StreamReader(fileStream))
{
string line = null;//初始化!
while ((line=streamReader.ReadLine())!=null)
{
string[] strs = line.Split('|');
string name = strs[0];
int age = Convert.ToInt32(strs[1]);
using (SqlConnection conn = new SqlConnection(@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321"))
{
conn.Open();
using(SqlCommand cmd=conn.CreateCommand())
{
cmd.CommandText = "insert into T_Persons(Name,Age) values(@Name,@Age)";
cmd.Parameters.Add(new SqlParameter("Name", name));
cmd.Parameters.Add(new SqlParameter("Age", age));
cmd.ExecuteNonQuery();
}
}
}
}
}
MessageBox.Show("導入成功!");
}
另一種簡單的方法:總結上面的代碼,由於創建連接非常費時,因此不要每次執行都建立連接!因此,針對這個問題進行解決!如下:
if (odfImport.ShowDialog()==DialogResult.No)//判斷用戶是否點取消按鈕!
{
return;
}
using (FileStreamfileStream=File.OpenRead(odfImport.FileName))
{
using (StreamReaderstreamReader=newStreamReader(fileStream))
{
using (
SqlConnectionconn=
newSqlConnection(
@"Data Source=.\MSSQL;Initial Catalog=Ado.net;Persist Security Info=True;User ID=taidou;Password=123321")
)
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="insert into T_Persons(Name,Age) values(@Name,@Age)";
stringline= null;
while ((line=streamReader.ReadLine()) !=null)
{
string[] strs=line.Split('|');
stringname=strs[0];
intage=Convert.ToInt32(strs[1]);
cmd.Parameters.Clear();//防止參數重復!在while循環中一直用的是SqlCommand對象!
cmd.Parameters.Add(newSqlParameter("Name", name));
cmd.Parameters.Add(newSqlParameter("Age", age));
cmd.ExecuteNonQuery();
}
}
}
}
}
MessageBox.Show("導入成功!");
18.選擇省市:(通過數據庫讀取)
這里注意一點:Form1類是繼承Form,如果要是再想建類,就必須寫在Form1類后面!
publicpartialclassForm1 : Form
{
publicForm1()
{
InitializeComponent();
}
privatevoidForm1_Load(objectsender, EventArgse) //實現當窗口彈出時就連接數據庫讀取數據!
{
/*Person pl =new Person();
pl.Name = "tom";
pl.Age = 30;
Person p2 = new Person();
p2.Name = "tom";
p2.Age = 30;
cmb省.Items.Add(pl);
cmb省.Items.Add(p2);
return;*/ //注釋的代碼主要是說明程序執行過程中,調用的是ToString()方法!
using (SqlConnectionconn=newSqlConnection(@"Data Source=.\MSSQL;Initial Catalog=MobPhoneQuery;Persist Security Info=True;User ID=taidou;Password=123321"))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select * from promary"; //讀取promary(省)表中的數據!
using (SqlDataReaderdataReader=cmd.ExecuteReader())
{
while (dataReader.Read())
{
ProvinceItemitem=newProvinceItem();
item.Id=dataReader.GetInt32(dataReader.GetOrdinal("proID"));
item.Name=dataReader.GetString(dataReader.GetOrdinal("proName"));
cmb省.Items.Add(item);
}
}
}
}
}
//隨着省份的改變,市也隨之改變!當用戶選擇好省份之后,將執行下列代碼!
privatevoidcmb省_SelectedIndexChanged(objectsender, EventArgse)
{
//cmb省.SelectedItem的類型是object類!
ProvinceItemitem= (ProvinceItem) cmb省.SelectedItem;
intproID=item.Id;
using (SqlConnectionconn=newSqlConnection(@"Data Source=.\MSSQL;Initial Catalog=MobPhoneQuery;Persist Security Info=True;User ID=taidou;Password=123321"))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select * from city where proID=@proID ";
cmd.Parameters.Add("proID", proID);
using (SqlDataReaderdataReader=cmd.ExecuteReader())
{
while (dataReader.Read())
{
stringcityName=dataReader.GetString(dataReader.GetOrdinal("cityName"));
cmb市.Items.Add(cityName);
/* ProvinceItem item = new ProvinceItem();
item.Id = dataReader.GetInt32(dataReader.GetOrdinal("proID"));
item.Name = dataReader.GetString(dataReader.GetOrdinal("proName"));
cmb省.Items.Add(item);*/
}
}
}
}
}
}
internalclassProvinceItem
{
publicstringName { get; set; }
publicintId { get; set; }
}
當沒設置窗體的屬性DisplayMember屬性時,直接給Person設置Name、Age屬性,系統會調用ToString()方法,即輸出結果是:"命名空間.類名"要想按要求輸出對象的屬性值,就必須擁有自己的ToString()方法!下列標注代碼就是起這種作用!
/* internal class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return Name;
}
}*/
}
-
將連接字符串寫在"應用程序配置文件"中
寫在配置文件的優點是:當客戶將服務器的ID地址修改后,我們就不用修改代碼來修改.exe文件。可以直接修改.exe.config文件中的字符串就可以了!
為了方便修改,我們也可以將字符串作為一個常量來看待。但是當服務器的Ip修改后,還是要修改代碼才能修改.exe文件!
1.首先添加"應用程序配置文件"即"App.config"文件,然后再文件中寫入下列代碼:
<connectionStrings>
<add name="ConStr" connectionString="Data Source=TAIDOU-PC\MSSQL;Initial Catalog=MobPhoneQuery;Persist Security Info=True;User ID=taidou;Password=123321"/>
</connectionStrings>
說明:標注的字符串是連接字符串;
其中的name可以自己命名;
2. 然后必須添加引用才能使用ConfigurationManager
添加步驟如下:
點擊添加引用,即添加:"usingSystem.Configuration"
然后在連接代碼前面添加如下代碼:
string conStr = ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
3.然后替換連接字符串就可以了!
19.手機附屬地查詢:
btnImport為數據導入按鈕:
privatevoidbtnImport_Click(objectsender, EventArgse)
{
//創建"文件夾選擇對話框"實例;
FolderBrowserDialogdlg=newFolderBrowserDialog();
//對話框結果是否為"ok"
if (dlg.ShowDialog() !=DialogResult.OK)
{
return;
}
//得到文件夾的路徑
stringpath=dlg.SelectedPath;
stringconnStr=ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString;
using (SqlConnectionconn=newSqlConnection(connStr))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="delete from T_Phone";
cmd.ExecuteNonQuery();
}
}
//Directory.GetFiles(文件路徑, "*.文件格式", SearchOption.AllDirectories)其中的SearchOption.AllDirectories是導入路徑下的所有符合文件格式的文件,包括其中的子文件下的格式文件!
string[] files=Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories);
using (SqlConnectionconn=newSqlConnection(connStr))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="insert into T_Phone(StartNo,EndNo,Name) values(@startno,@endno,@name)";
foreach (stringfileinfiles)
{
//得到目錄下文件的文件名
string運營商名稱=Path.GetFileNameWithoutExtension(file);
string[] lines=File.ReadAllLines(file, Encoding.Default);//不用StreamReader,因為文件很小,一次性加載也不占多少內存。如果是大文件的話,使用StreamReader比較方便!
//這里的ReadAllLines的意思是:"讀取所有行",經反編譯得知:它的默認編碼是"UTF-8"。
foreach (stringlineinlines)
{
string[] strs=line.Split('-');
string開始號碼=strs[0];
string結束號碼=strs[1];
string市=strs[2];
cmd.Parameters.Clear();
cmd.Parameters.Add(newSqlParameter("startno", 開始號碼));
cmd.Parameters.Add(newSqlParameter("endno", 結束號碼));
cmd.Parameters.Add(newSqlParameter("name", 運營商名稱+市));
cmd.ExecuteNonQuery();
}
MessageBox.Show("導入成功!");
}
}
}
}
btnSearch是搜索按鈕,
privatevoidbtnSearch_Click(objectsender, EventArgse)
{
stringconnStr=ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString;
using (SqlConnectionconn=newSqlConnection(connStr))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select * from T_Phone where StartNo<=@No and EndNo>=@No ";
cmd.Parameters.Add(newSqlParameter("No", txtPhone.Text));
using (SqlDataReaderreader=cmd.ExecuteReader())
{
if (reader.Read())
{
stringname=reader.GetString(reader.GetOrdinal("Name"));
MessageBox.Show("手機歸屬地:"+name);
}
else
{
MessageBox.Show("找不到運行商信息!");
}
}
}
}
}
-
嘗試封裝:
//params的意思是該參數是可變的!//執行非查詢語句!
publicstaticintExecuteNonQuery(stringsql, paramsSqlParameter[] parameters)
{
stringconnStr=ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
using (SqlConnectionconn=newSqlConnection(connStr))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText=sql;
foreach (SqlParameterparameterinparameters)
{
cmd.Parameters.Add(parameter);
}
returncmd.ExecuteNonQuery();
}
}
}
調用如下:
privatevoidbutton1_Click(objectsender, EventArgse)
{
SQLHelper.ExecuteNonQuery("insert into T_Persons(Name,Age) values(@Name,@Age)",
newSqlParameter("Name", "tom"), newSqlParameter("Age", 32));
MessageBox.Show("插入成功!");
}
//顯示第一行第一列的數據!
publicstaticobjectExecuteScalar(stringsql, paramsSqlParameter[] parameters)
{
stringconnStr=ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
using (SqlConnectionconn=newSqlConnection(connStr))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText=sql;
foreach (SqlParameterparameterinparameters)
{
cmd.Parameters.Add(parameter);
}
returncmd.ExecuteScalar();
}
}
}
調用如下:
privatevoidbutton2_Click(objectsender, EventArgse)
{
//由於ExecuteScalar()的返回值(即第一行第一列)類型是Object類型!所以為object;
objecti=SQLHelper.ExecuteScalar("select count(*) from T_Persons");
//這里注意MessageBox.Show()方法不能得到int類型的變量,所以雖然其中的i為int類型,也不能調用Convert.Toint32(i)
MessageBox.Show(Convert.ToString(i));
}
注意:ExecuteReader不能使用前面的方法!因為當斷開連接后就不能讀取表中的數據了!
如下:
//不能用這個方法!因為一旦連接關閉,就不能用使用SqlDataReader進行讀取數據了!
publicstaticSqlDataReaderExecuteReader(stringsql, paramsSqlParameter[] parameters)
{
stringconnStr=ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
using (SqlConnectionconn=newSqlConnection(connStr))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText=sql;
foreach (SqlParameterparameterinparameters)
{
cmd.Parameters.Add(parameter);
}
returncmd.ExecuteReader();
}
}
}
··
應該使用如下方法:
publicstaticDataTableExecuteDataTable(stringsql, paramsSqlParameter[] parameters)
{
stringconnStr=ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
using (SqlConnectionconn=newSqlConnection(connStr))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText=sql;
foreach (SqlParameterparameterinparameters)
{
cmd.Parameters.Add(parameter);
}
DataSetdataset=newDataSet();
//執行SQL語句!
SqlDataAdapteradapter=newSqlDataAdapter(cmd);
//將執行后的結填充的dataset中!
adapter.Fill(dataset);、
//執行結果中包含多個表,返回表一!
returndataset.Tables[0];
}
}
}
調用如下L:
privatevoidbatton5_Click(objectsender, EventArgse)
{
DataTabledt=SQLHelper.ExecuteDataTable("select * from T_Persons");
//表里表中的每一行!
for (inti=0; i<dt.Rows.Count; i++)
{
DataRowrow=dt.Rows[i];
//得到行中Name數據!
stringname=Convert.ToString(row["Name"]);
MessageBox.Show(name);
}
}
驗證使用如上方法可以將表中的數據緩存到內存中從而以后可以讀取其中的數據!
private void batton4_Click(object sender, EventArgs e)
{
/*string connStr = ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from T_Persons";
DataSet dataset=new DataSet();
//執行SQL語句!
SqlDataAdapter adapter=new SqlDataAdapter(cmd);
//將執行后的結填充的dataset中!
adapter.Fill(dataset);
//執行結果中包含多個表!
DataTable table = dataset.Tables[0];
for (int i = 0; i < table.Rows.Count; i++)
{
//得到表中的行數據!
DataRow row = table.Rows[i];
//獲取表中行row["Name"]中的Name數據!
string name = Convert.ToString(row["Name"]);
MessageBox.Show(name);
}
}
}*/
DataSet dataset = new DataSet();
string connStr = ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select * from T_Persons";
//執行SQL語句!
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
//將執行后的結填充的dataset中!
adapter.Fill(dataset);
//執行結果中包含多個表!
}
}
DataTable table = dataset.Tables[0];
for (int i = 0; i < table.Rows.Count; i++)
{
//得到表中的行數據!
DataRow row = table.Rows[i];
//獲取表中行row["Name"]中的Name數據!
string name = Convert.ToString(row["Name"]);
MessageBox.Show(name);
}
}
這里注意雖然這種方法可以彌補ExecuteReader中的缺點,但是只針對於小型的數據,對於大數據不能使用這種方法,因為大數據會使內存爆滿的!
-
錯誤陷阱:
- //注意SqlParameter方法的參數類型多種多樣,其中有一個 public SqlParameter(string parameterName, SqlDbType dbType);這里的SqlDbType是一種枚舉類型,0正好是枚舉類型中的一個值,所以程序會匹配到該類型中。不會匹配到 public SqlParameter(string parameterName, object value);因此如果值為0時,應該將其轉化成Object類型!
SqlHelpes.ExecuteDataTble("select * from T_Login where Id=@id", newSqlParameter("Id", (Object)0));
-
在SqlConnection中,可以將連接永久保持打開嗎?
答:不可以。因為在連接數據庫中,連接是有限的,在用戶使用完之后,一定要將連接關閉。從而供給其他用戶使用!
-
修改Dataset(Dataset的更新):
DataSetdataset=newDataSet();
stringconnStr=ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
using (SqlConnectionconn=newSqlConnection(connStr))
{
conn.Open();
using (SqlCommandcmd=conn.CreateCommand())
{
cmd.CommandText="select * from T_Persons";
//執行SQL語句!
SqlDataAdapteradapter=newSqlDataAdapter(cmd);
//將執行后的結填充的dataset中!
adapter.Fill(dataset);
//執行結果中包含多個表!
DataTabletable=dataset.Tables[0];
//取出表中的第0行的數據!
DataRowrow=table.Rows[0];
//更改第0行數據中的Name項!
row["Name"] ="jasion";
// table.Rows.RemoveAt(1);//這句話的意思是刪除第1行的數據!
//table.NewRow();//這句話的意思是添加新的行數!
以上對行的修改都是更改內存中的數據!對數據庫沒有影響!要想修改數據庫中的數據,可以使用如下兩句話就可以了!
SqlCommandBuilderbuilder=newSqlCommandBuilder(adapter);//修改命令!
adapter.Update(dataset);//更新dataset中的數據,同時更改數據庫中的數據!
}
}
-
可空的值類型:
所謂的可空的值類型就是就是在類型的后面添加一個問號即(?)就代表該類型是可空的類型!
staticvoidMain(string[] args)
{
//下面的不允許
//int n1 = null;
//下面的可以!
int?no=1;
int?ni=null;
int?i=null;
if (i==null)
{
Console.WriteLine("i為空!");
}
else
{
i++;
//在這里雖然經過了else但是,畢竟i定義的是可能為空的,所以將可能為空的變量賦值給絕對不為空的變量時,必須強制轉化!
int i1 = (int)i;
Console.WriteLine("i不為空!i++={0}",i);
}
//如果i有值,則說明i不為空,否則為空!
if (i.HasValue)
{
//將i的值賦給其他變量!
int i1 = i.Value;
Console.WriteLine("i不為空!");
}
else
{
Console.WriteLine("i為空!");
}
}
這里注意:可以將一個一定為空的變量賦值給一個可能為空的變量,但相反就不可以!
-
弱類型Dataset的缺點:
- 只能通過列名來引用,如果寫錯了列名編譯時發現不了錯誤,只有運行時才能發現錯誤,因此開發時必須要記着列名才行!
- Int age=Convert.ToInt32(dataset.Rows[0]["Age"]),取得字段的值是Object類型,必須小心翼翼的進行類型轉換才行,這樣不僅麻煩,而且容易出錯!
- 將Dateset傳遞給其他使用者,使用者很難識別有哪些列可以使用!
- 運行時才能知道所有列名,數據綁定麻煩,無法使用Winform、Asp.Net的快速開發功能!
因此為了彌補弱類型Dataset,我們引出了強類型的Dataset!
-
手動制作強類型的Dataset
首先添加一個類,比如叫做T_UsersRow
假如數據庫中有一個名為T_User的表,表中有兩個字段分別是:Id和UserName,然后我們就可以這樣寫了:
classT_UsersRow:DataRow
{
publicintId
{
get
{
returnConvert.ToInt32(this["Id"]);
}
set
{
this["Id"] =value;
}
}
publicstringUserName
{
get
{
returnConvert.ToString(this["UserName"]);
}
set
{
this["UserName"] =value;
}
}
}
-
讓程序自動將弱類型的Dataset轉化成強類型的Dataset:
-
添加數據集,將表拽到數據集中,程序就會自動生成!並且會自動產生連接文件"App.config"文件!里面的連接字符串也自動產生!
如下:
-
privatevoidbutton1_Click(objectsender, EventArgse)
{
T_PersonTableAdapteradapter=newT_PersonTableAdapter();
/* DataSetPersons.T_PersonDataTable persons = adapter.GetData();
for (int i = 0; i <= persons.Count; i++)
{
DataSetPersons.T_PersonRow person = persons[i];
string msg = string.Format("姓名:{0},年齡:{1}", person.Name, person.Age);
//中的Name項1!
person.Name = "aaa";
//更新據庫
adapter.Update(persons);
MessageBox.Show(msg);
}*/
//直接調用插入方法,插入數據!
adapter.Insert("taidou", 12);
}
強類型的缺點:
修改字段后,必須重新配置生成!
所以強類型Dataset不一定就很強,所以還是將其叫做"類型化Dataset(Typed Dataset)比較好!
privatevoidbutton1_Click(objectsender, EventArgse)
{
T_PersonTableAdapteradapter=newT_PersonTableAdapter();
DataSetPersons.T_PersonDataTablepersons=adapter.GetData();
//行的數據!
DataSetPersons.T_PersonRowp=persons[0];
//MessageBox.Show(p.Name);
//如果p的name列為空!
if (p.IsNameNull())
{
MessageBox.Show("名字為空!");
}
else
{
MessageBox.Show(p.Name);
}
/* for (int i = 0; i <= persons.Count; i++)
{
DataSetPersons.T_PersonRow person = persons[i];
string msg = string.Format("姓名:{0},年齡:{1}", person.Name, person.Age);
person.Name = "aaa";
adapter.Update(persons);
MessageBox.Show(msg);
}
adapter.Insert("taidou", 12);*/
}
******如何重新配置生成:
- 在數據集文件上面右擊,選擇"配置",如果你是更改現有字段里面的一些屬性,那么你可以直接點擊"完成"按鈕就可以!
-
如果你添加了一些字段,那么你應該點擊"查詢生成器",將你要添加的字段勾選上,然后再點擊完成就可以了!
如下圖:
到此重新配置就完成了!
******在強類型的(類型化的)Dataset中,手寫自己的SQL語句!
- 在數據集文件上面右擊,選擇"添加"-》"查詢"。
-
使用默認選項(使用SQL語句(S)),點擊"下一步"!
如圖:
-
如圖中:
含有"更新"、"刪除"、"插入"、"查詢語句"
在查詢中,含有"返回行"和"返回單個值"相當於"ExecuteScalar()".
以上就是操作步驟,我們只要在其后面添加where語句就可以了!如果默認含有where語句,我們可以根據自己的需求進行刪減!
-
處理批量數據只在一個連接中處理耗時短~!
privatevoidbutton1_Click(objectsender, EventArgse)
{
Stopwatchsw=newStopwatch();
sw.Start();
T_LoginTableAdapteradapter=newT_LoginTableAdapter();
//對於大量數據使用這種方法,因為每次都要打開和關閉連接!所用時間為24秒!
/* for (int i = 0; i <= 3000; i++)
{
adapter.Insert(i.ToString(), i.ToString(), 0);
}
*/
adapter.Connection.Open();
for (inti=0; i<3000; i++)
{
adapter.Insert(i.ToString(), i.ToString(), 0);
}
adapter.Connection.Close();
sw.Stop();
MessageBox.Show(sw.Elapsed.ToString());
}
-