ADO.NET基础笔记
-
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());
}
-