第十六天ADO.NET(通过C#代码对数据库操作)
PS:vs所需连接的服务器名称“LYY\SQLEXPRESS”
实例化SqlConnection添加命名空间ctrl+.
一.简单介绍
1.为什么学ADO.NET
之前我们所学只能在查询分析器里查看数据,操作数据,我们不能让普通用户去学sql,所以我们搭建一个界面(Web Winform)让用户方便的操作数据库中的数据
2.什么事ADO.NET
ADO.NET就是一组类库,这组类库可以让我们通过程序的方式访问数据库,就像System.IO下的类用类操作文件一样, System.Data.这组类是用来操作数据库(不光是MSSql Server),它提供了统一的编程接口让操作其它数据库(Access、Oracle等)的方式和操作MSSqlServer一致
二.ADO内的类
1.常见类
Connection,用来连接数据库
Command,用来执行SQL语句
DataReader只读、只进的结果集,一条一条读取数据(StreamReader微软的类库中这些Reader的使用方式都差不多)
DataAdapter,一个封装了上面3个对象的对象
2.不常见类
ConnectionStringBuilder//自动生成连接字符串
Parameter//带参数的SQL语句
Transaction//在ADO.NET中使用事务
三.获取连接字符串
1.鼠标点点
视图—其他窗口—服务资源管理器—添加链接—选择数据库名称—获得链接字符串
2.手写代码连接
两种代码方式(连接字符串)
string sql = "Data Source=服务名称;Initial Catalog=数据库;IntegratedSecurity=True"; //采用windows验证
string sql = "Data Source=服务名称;Initial Catalog=数据库;Userid=sa;password=123"; //采用用户验证
3.通过方法自动组合
SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder();
scsb.DataSource =@"LYY\SQLEXPRESS";
scsb.InitialCatalog = "mydatabase";
scsb.IntegratedSecurity =true;
Console.WriteLine(scsb.ToString());
Console.ReadKey();//scsb内存的便是连接字符串
4.自己输入数据通过winform进行显示使用PropertyGrid控件的SelectedObject属性与SqlConnectionStringBuilder配合使用。
private void Form1_Load(objectsender, EventArgs e)
{
SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder();
ppg.SelectedObject = scsb;
}
private void button1_Click(object sender, EventArgs e)
{
SqlConnectionStringBuilder scsb= ppg.SelectedObject as SqlConnectionStringBuilder;
MessageBox.Show(scsb.ToString());
}
//ppg为PropertyGrid控件的名字
四.连接数据库及对数据库的简单操作(using,SqlConnection,SqlCommand)
1.第一步应先判断是否打开了数据库
if (con.State=="open")
{
//便不重新打开数据库
//内部填以下代码 }
else
{
//便重新打开数据库
con.open();
} 1 . / /连接数据库
//第一步写连接字符串
2代码
string str = @"Data Source=LYY\SQLEXPRESS;Initial Catalog=MyDatabase;IntegratedSecurity=True";
int number = -1;
using (SqlConnection con = new SqlConnection(str))//连接数据库
{//使用using不用再调用方法进行清除缓存
string sql = "updatetblstudent set tsgender='女' where tsid=2";//SQL语句
using (SqlCommand com = new SqlCommand(sql,con))//执行SQL语句
{
con.Open();//打开数据库
number=com.ExecuteNonQuery();//显示几行受影响
}
}
Console.WriteLine(number);
Console.ReadKey();
3.若远程连接时报异常,则用try catch解决
五.两个对象(前面加Sql)
1. 第一个对象Connection
如何连接数据库,需要连接字符串
获取连接字符串的方式:
VS视图-服务器资源管理器-数据库连接上点右键-添加连接 在新添的数据库上点右键 属性 里有连接字符串
使用SqlConnectionStringBuilder帮助获取连接字符串
使用PropertyGrid控件的SelectedObject属性与SqlConnectionStringBuilder配合使用。
打开连接.(多次打开问题:ConnectionState枚举)
关闭连接 //相当于设置了路障
释放资源 //相当于把路拆了,这块地可以盖楼了。
调用Connection.Dispose()【继承自Component类的方法】方法时,内部调用了Close();connection不能重复打开
2. 第二个对象Command
如何执行sql语句,需要执行sql语句的对象
操作Sql Server数据库使用SqlCommand对象,
SqlCommand表示向服务器提交的一个命令(SQL语句等) , CommandText属性为要执行的SQL语句.
创建SqlCommand对象: 通过new关键字创建
使用后同样需要 关闭 释放 资源,
所以同样可以使用using
下面掩饰sqlConnection,sqlcommand,以及三种方法
六.常用三个方法
增删改:ExecuteNonQuery() 执行对数据库的增删改,返回受影响的行数,适合:insert、delete、update(对于其他语句返回-1)
//cmd.该方法,相当于执行了SQL语句,如果不写这个或其余两个则相当于SQL没有执行。
首行首列:ExecuteScalar() 执行查询,返回首行首列,和聚合函数一起使用
--SqlCommand的ExecuteScalar方法用于执行查询,并返回查询所返回的结果集中第一行的第一列,因为不能确定返回值的类型,所以返回值是object类型。//ExecuteScalar()方法内部也是调用ExecuteReader()实现的。
cmd.CommandText = "select count(*)from student";int i = Convert.ToInt32(cmd.ExecuteScalar())
cmd.CommandText = "select getdate()";DateTime dt = Convert.ToDateTime(cmd.ExecuteScalar());
读取每一行:ExecuteReader() 执行查询,返回DataReader用using,hasrows属性判断
----.reader的对象可以通过索引
- -- ---执行有多行结果集的用ExecuteReader
-----HasRow属性返回是否有行
SqlDataReader reader =cmd.ExecuteReader();...
while (reader.Read())
{
Console.WriteLine(reader.GetString(1));
}
-----reader的GetString、GetInt32等方法只接受整数参数,也就是序号,用GetOrdinal方法根据列名动态得到序号
--更简单的方法reader[‘uUserName’]
-----为什么用using。Close:关闭以后还能打开。Dispose:直接销毁,不能再次使用。using在出了作用域以后调用Dispose,SqlConnection、 SqlDataReader等的Dispose内部都会做这样的判断:判断有没有close,如果没有Close就先Close再Dispose。
-----DataReader 必须独享一个Connection 。 (除非设置了允许MARS,多活动结果集,在连接字符串中)
-----使用reader的时候要保证sqlconnection是开着的,使用reader后要关闭,reader需要独占一个数据库连
//在循环里一定要使用索引来获取数据
//在循环里一定不要用列名获取数据
//代码就不用改了
int m=sqlreader.GetOrdinal("name");//获取列的编号索引
sqlreader.GetInt16(m);//根据索引获取列
七.增删改查大项目的技巧
1. stringsql = string.Format("INSERT INTOtblstudent(tSName,tSGender,tSAge,tSPhone,tsclassid)VALUES ('{0}','{1}',{2},'{3}',{4})",name,gender,age,phone,1);
2.将每一行的数据储存到一个对象里面(关系转对象)
using (SqlDataReader reader= com.ExecuteReader())
{ //采用该方法执行查询,返回对象
if (reader.HasRows)
{ //判断是否读取到了行数,行数大于0则返回true
while (reader.Read())
{ //一行一行的读取数据读取数据
Student stu = newStudent();
stu.TsId =reader.GetInt32(0);
stu.TsName = reader[1].ToString();
//reader【】类似数组,从0开始存的为这一行每一列的数据
stu.TsGender =reader[2].ToString();
stu.TsAge =reader.GetInt32(3);
stu.TsPhone =reader[4].ToString();
lists.Add(stu);
}
}
}
3.控件是否隐藏的属性:visible
4.以laber控件的Text保存一个值,进行传递,并将该控件的属性设置为隐藏
5.添加控件中RowEnter方法,将数据显示到一些文本框中
private void dgv_RowEnter(object sender, DataGridViewCellEventArgs e)
{
if (dgv.SelectedRows.Count>0)
{
lbId.Text =dgv.SelectedRows[0].Cells[0].Value.ToString();
txtUPName.Text =dgv.SelectedRows[0].Cells[1].Value.ToString();
txtUPGender.Text =dgv.SelectedRows[0].Cells[2].Value.ToString();
txtUPAge.Text =dgv.SelectedRows[0].Cells[4].Value.ToString();
txtUPPhone.Text =dgv.SelectedRows[0].Cells[3].Value.ToString();
}
}
6.一个套路
if (dgv.SelectedRows.Count>0)
{
int number1 = -1;
string id =dgv.SelectedRows[0].Cells[0].Value.ToString();//value至关重要
string str = @"Data Source=lyy\SQLEXPRESS;InitialCatalog=mydatabase;Integrated Security=true";
using (SqlConnection con=new SqlConnection(str))
{
string sql = "deletefrom tblstudent where tsid="+id;
using (SqlCommand com=new SqlCommand(sql,con))
{
con.Open();
number1 =com.ExecuteNonQuery();
}
}
if (number1 > 0)
{
NewMethod();
MessageBox.Show("删除成功!");
}
else
{
MessageBox.Show("删除失败!");
}
八.异常处理
1.
在执行数据库操作时,如果数据库服务器未打开,或者sql语句写错了会怎么样?
con.Open();cmd.Execute….();
可以使用try…catch…finally来捕获异常
使用异常处理可以保证一个功能出错不影响另一个功能,比如添加操作失败,不影响查询的操作
2.代码:
try
{
//打开连接
conn.Open();
//执行操作
result = cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
//关闭连接
conn.Close();
}
九.SqlDataReader,ExecuteReader,HasRows,Read.的组合应用和GetOrdinal()的应用
static void Main(string[] args)
{
string str = @"Data Source=lyy\SQLEXPRESS;InitialCatalog=mydatabase;Integrated Security=true";
using (SqlConnection con=new SqlConnection(str))
{
string sql = "selecttsname,tsgender,tsage from tblstudent";
using (SqlCommand com = new SqlCommand(sql,con))
{ //打开数据库(SqlDataReader独占一个打开的连接)
con.Open();
//这一步至关重要,弄个出来个SqlDataReader对象
SqlDataReader sd= com.ExecuteReader();
//判断
if (sd.HasRows)
{ //获取tsage的所在列的索引
int index =sd.GetOrdinal("tsage");
//读取数据
while (sd.Read())
{
//字符串的两种方法,根据索引
string name = sd[0].ToString();
string gender =sd.GetString(1);
string name= sd[“列名”]//也可以获取值
//int类型的使用该方法
int age =sd.GetInt32(index);
//使用占位符
Console.WriteLine("{0}==={1}==={2}",name,gender,age);
}
}
}
}
Console.ReadKey();
}
十.ADO.NET连接池
1.简介:由于每次正常连接数据库都会至少执行3个操作(1.登录数据库服务器2.执行操作3.注销用户),所以每次通过Connection向数据库服务器申请一个连接都比较耗时。
2.作用:当你的连接字符串和池子里面的一样是就会调用池子里面原本就有的。不会重新打开一次。这样就会运行速度加快。
3.ADO.NET会默认启用连接池。
4.数据库的启动情况可在SQL Server里面的工具选项中的第一个选项中查看
5.禁用的代码,string str = @"DataSource=LYY\SQLEXPRESS;Integrated Security=True;pooling=false";//在后面加上pooling=false字眼即可。
6.什么时候禁用连接池
一般都不禁用。尤其是asp.net之类的程序,n多个用户频繁访问,但是大多数用户访问时采用的都是同一个连接字符串
但如果某个应用程序有多个客户端,每个客户端访问时采用的都是各自的连接字符串,这时如果采用连接池,虽然每次打开连接的速度会变快,但是由于“池”的问题同时会保存多个打开的连接对象。
7.连接池的原理总结
1.第一次打开连接会创建一个连接对象。
2.当这个连接关闭时(调用Close()方法时)会将当前那个连接对象放入池中。
3.下一个连接对象,如果连接字符串与池中现有连接对象的连接字符串完全一致,则会使用池中的现有连接,而不会重新创建一个。
4.只有对象调用Close(),的时候才会放入池中,如果一个连接对象一直在使用,则下次再创建一个连接对象发现池中没有,也会再创建一个新连接对象。
5.在池中的连接对象,如果过一段时间没有被访问则自动销毁。
十一:SQL注入漏洞攻击(连接的数据库)
1. 若想SQL注入在账户名后加上“' or1=1--”字符串。
2. 例如xycs' or 1=1—Sql语句意思变为:账号等于xycs并且1=1,--后面的注释掉。
3. 防范注入漏洞攻击的方法:不使用SQL语句拼接,通过参数赋值
参数在SQLServer内部不是简单的字符串替换,SQLServer直接用添加的值进行数据比较,因此不会有注入漏洞攻击。(带参数的sql语句内部是调用了存储过程)
使用事件查看器查看。
SQL Server仅支持已命名参数@arg1,而Oledb、Odbc仅支持通用参数标记(?),不同数据提供程序对参数的写法可能不同。
4.登陆案例
5.可以注入与防止注入的代码:
//SQL注入的语句
using (SqlConnection con = new SqlConnection(str))
{
string sql = string.Format("SELECTCOUNT(*) FROM users WHERE unname='{0}' and upwd='{1}'", name, pwd);
using (SqlCommand com = new SqlCommand(sql,con))
{
con.Open();
count = Convert.ToInt32(com.ExecuteScalar());
}
}
//防止SQL注入的语句
using (SqlConnection con = new SqlConnection(str))
{
string sql = "SELECTCOUNT(*) FROM users WHERE unname=@name and upwd=@pwd"; ---不需要单引号了,不需要占位符了,不需要Format(使格式化的意思)函数啦
using (SqlCommand com = new SqlCommand(sql,con))
{
con.Open();
com.Parameters.AddWithValue("@name",name);
com.Parameters.AddWithValue("@pwd",pwd);
//parameter为参数的意思
count = Convert.ToInt32(com.ExecuteScalar());
}
}
//将SQL语句中的占位符和string.Farmat()去掉,替换为参数成为真正的字符串,上述代码中“@name”“@pwd”便为参数,之后再将Parameters.AddWithValue()函数对参数进行赋值。
十二: 从今以后SQL全都写为参数形式
给参数赋值的三种方法:
//第一种
com.Parameters.Add(new SqlParameter("@name",name));
com.Parameters.Add(new SqlParameter("@pwd",pwd));
//第二种
com.Parameters.AddWithValue("@name", name);
com.Parameters.AddWithValue("@pwd", pwd);
//第三种
com.Parameters.AddRange(new SqlParameter[]
{ new SqlParameter("@name",name), new SqlParameter("@pwd ", pwd)});
十三:导入导出数据库数据
1.将数据库的数据导出
//前面为连接数据库的套路
using (SqlDataReader sda= com.ExecuteReader())
{
if(sda.HasRows)
{
//创建一个流对象,用于写入数据
using(StreamWriter sw=new StreamWriter("1.txt"))
{
//用SqlDataReader的对象调用GetName()函数得到列名,并写入列名
sw.WriteLine("{0},{1}",sda.GetName(0), sda.GetName(1));
//读取
while (sda.Read())
{
//写入文本中,用索引的方式得到值
sw.WriteLine("{0},{1}", sda["uname"],sda["uage"]);
}
}
}
2.将数据导入到数据库
using(SqlCommand com=new SqlCommand(sql,con))
{
con.Open();
//设置每个参数的类型
SqlParameter[] param =
{
new SqlParameter("@uname",System.Data.SqlDbType.NVarChar),
new SqlParameter("@uage",System.Data.SqlDbType.Int),
new SqlParameter("@ugender",System.Data.SqlDbType.NChar),
};
//给参数赋值
com.Parameters.AddRange(param);
while((line=sr.ReadLine())!=null)
{
//将逗号切掉
string[] strs =line.Split(',');
//赋值给该数组
param[0].Value =strs[0];
param[1].Value =strs[1];
param[2].Value =strs[2];
//执行SQL语句,不用接受返回值
com.ExecuteNonQuery();
}
}//end using
十四:SQL封装自定义SQLHelper类和App.config文件
PS:App.config + SQLHelper + 带参数的SQL语句(SH的使用)
1.封装连接字符串App.config文件,一个项目只能有一个该文件
在该项目中添加应用程序配置文件
//自定义名称
2.封装三种常见方法SQLHelper类(将他们封装在一个类中,该类要添加引用,在程序集中的System。Configuration再添加该命名空间,
//创建连接字符串,以后直接用str变量代表字符串即可
static readonly string str = ConfigurationManager.ConnectionStrings["strCon"].ConnectionString;
//封装方法ExcuteNonQuery
//在主程序中直接类名调用即可,第二个参数可以为空,即可以只传第一个参数
public static int ExcuteNonQuery(string sql,paramsSqlParameter[]param)
{
using (SqlConnection con=new SqlConnection(str))
{
using (SqlCommand com=new SqlCommand(sql,con))
{
con.Open();
//判断是否有参数
if (param!=null)
{
//将参数添加进去
com.Parameters.AddRange(param);
}
returncom.ExecuteNonQuery();
}
}
}
///封装第二个方法ExcuteScalar
public static object ExcuteScalar (string sql,params SqlParameter[]param)
{
using (SqlConnection con=new SqlConnection(str))
{
using (SqlCommand com=new SqlCommand(sql,con))
{
con.Open();
if (param!=null)
{
com.Parameters.AddRange(param);
}
return com.ExecuteScalar();
}//end usig
}//end using
}//end
//封装第三个方法ExcuteReader
public static SqlDataReader ExcuteReader(stringsql,params SqlParameter[]param)
{
//不使用using是因为要处异常,手动关闭即可
SqlConnection con = new SqlConnection(str);
using (SqlCommand com=new SqlCommand(sql,con))
{
if (param!=null)
{
com.Parameters.AddRange(param);
}
try
{
con.Open();
//关闭连接,运用括号里的东西,相当于using的作用了
returncom.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
con.Close();
con.Dispose();
throw ex;//抛出ex,是给程序员看的
}
}
}
3.SQLHelper了自定义类的补充
1.在封装返回SqlDataReader的方法中关于Connection的关闭、异常与资源释放问题:
当使用using时可以不加try-catch,但是在返回SqlDataReader的方法中没有使用using,所以这时应该增加一个try-catch,防止发生异常后无法关闭连接对象。
2. 网上有微软提供的最全的SQLHelper类,是Enterprise Library中的一部分
3. sqlconnection在程序中一直保持它open可以吗?对于数据库来说,连接是非常宝贵的资源,一定要用完了就close、dispose。【Close以后就可以放到“池”中了,其他链接就可以再次使用了。】
4. 通过执行ExecuteReader()方法获取输出参数的时候需要将reader.Close()以后才能获取
第十八天
一:技巧
1.当显示内容为命名空间时,若想显示内容时
重写(override)Tostring()函数。代码如下:
public override string ToString()
{
return this.AreaName;
}
2.控件显示“请选择“字样的方法
comboBox1.Items.Add(new Area() { AreaId = -1, AreaName = "请选择" });
//area为一个对象
comboBox1.SelectedIndex = 0;
//显示第一行
3.想要拿到控件选定时的数据,可将其转换为所需对象用as
Areaarea= comboBox1.SelectedItem as Area;
4.清空combox控件数据的方法,避免重复显示
comboBox2.Items.Clear();
5.在递归方法的括号中调用方法
LoadGategory(GetCatagoryBytfrientId(item.TId),tn.Nodes);
6.加载数据库中的数据的其中一个套路
private List
{
List
string sql = "SELECT tID,TName FROM category WHERE tparentid="+ v;
SqlDataReader reader= SQLHelper.ExcuteReader(sql);
if (reader.HasRows)
{
while (reader.Read())
{
Category category = new Category();
category.TId = Convert.ToInt32(reader["tid"]);
category.TName = reader["tName"].ToString();
list.Add(category);
}
}
7.若需要一些数据,可以将控件中选定的数据转换为所需对象的类型
ContentInfo con= listBox1.SelectedItem as ContentInfo;
textBox1.Text = GetContentInfoText(con.DId);
8.显示选定数据的内容。定义一个方法,返回查询后的首行首列
private stringGetContentInfoText(int id)
{
string sql = "SELECT dcontent FROM Contentinfo WHERE did=" +id;
return SQLHelper.ExcuteScalar(sql).ToString();
}
二:Dataset(资料组的意思)需要命名空间using System.Data;
1.简介:
DataSet是ADO.NET的中心概念。可以把DataSet当成内存中的数据库,DataSet是不依赖于数据库的独立数据 ,DataSet对于多层应用程序之间传递数据。(现在大都用List
2.SqlDataReader与Dataset的不同之处
SqlDataReader是连接相关的,SqlDataReader中的查询结果并不是放到程序中的,而是放在数据库服务器中,SqlDataReader只是相当于放了一个指针(游标),只能读取当前游标指向的行,一旦连接断开就不能再读取。这样做的好处就是无论查询结果有多少条,对程序占用的内存都几乎没有影响。
SqlDataReader为速度而生,只读、只进,功能有限。ADO.Net中提供了数据集的机制,将查询结果填充到本地内存中,这样连接断开、服务器断开都不影响数据的读取。
2.新创建临时数据库,表,列,行
DataSet ds = new DataSet("Person");//创建的临时数据库
DataTable dt = new DataTable("Student");//表
DataColumn dc1 = new DataColumn("id", typeof(int));//列
dc1.AutoIncrement = true;//将dc1这一列设定为自增
dc1.AutoIncrementSeed = 1;
dc1.AutoIncrementStep = 1;
DataColumn dc2 = new DataColumn("name", typeof(string));//列
dt.Rows.Add("haha");//行
3.建立表,列,行de关系
ds.Tables.Add(dt);//将表添加到临时数据库中
dt.Columns.Add(dc1);//将列添加到表中
dt.Columns.Add(dc2);
dt.Rows.Add(1,"haha");//将行添加到表中
4.遍历输出表名,列名,行数据
foreach (DataTable item inds.Tables)//遍历表名
{
Console.WriteLine(item.TableName);
foreach (DataRow row indt.Rows)//遍历行数据
{
Console.WriteLine(row[0].ToString()+row[1]);
}
foreach (DataColumn col indt.Columns)//遍历列名
{
Console.WriteLine(col.ColumnName);
}
}
三:神奇的一段代码(将数据库里面的东西显示出来的简便方法)(SqlDataAdapter方法)
1.未封装为方法的时候
private void Form1_Load(object sender, EventArgse)
{
//创建一个表的对象
DataTable dt = new DataTable();
string sql = "select * from tblstudent";
string con = @"Data Source=LYY\SQLEXPRESS;InitialCatalog=MyDatabase;Integrated Security=True";
//SqlDataAdapter方法里面封装了SqlConnect等方法
using (SqlDataAdapter sda = new SqlDataAdapter(sql, con))
{
sda.Fill(dt);//将读取的数据填充到dt表里面
}
dataGridView1.DataSource = dt;
}
2.封装为方法(封装在一个类里面)
public class SQLHelper
{
private static readonly string str = "DataSource=lyy\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=true";
public static DataTable GetTableText(string sql,params SqlParameter[]param)
{
DataTable table = new DataTable();
using (SqlDataAdapter sda=new SqlDataAdapter(sql,str))
{
sda.Fill(table);
}
return table;
}
}
四:comboBox控件的两大属性
1.DisplayMember属性,选择要显示的内容
2.ValueMember属性,记录下来需隐藏的内容
3.注意事项:ComboBox的数据源绑定方法,会触发“选择项改变事件”,不要将DataSource绑定写在前面
4.代码:
private void Form1_Load(objectsender, EventArgs e)
{
string sql = "select tclassid,tclassname from tblclass";
DataTable table= SQLHelper.GetDatabaseText(sql);
//写入隐藏属性,已经存在里面了
comboBox1.ValueMember = "tclassid";
//指出所需显示的内容,只是单纯的指示
comboBox1.DisplayMember = "tclassName";
//最后一步再将表写入到控件中
comboBox1.DataSource = table;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//显示出Value值,SelectValue
MessageBox.Show(comboBox1.SelectedValue.ToString());
}
五:空值处理
DBNull类,以后介绍。
第二十天
一:补充
//怎样执行数据库中的存储过程
string sql = "execusp_ChengFa @sum output";
using (SqlCommand cmd = new SqlCommand(sql))
{
con.Open();
//下面这行语句可以设置当前执行的是sql语句还是存储过程
cmd.CommandType = CommandType.StoredProcedure;//设置的为存储过程
//若在事务里面有output修饰的参数,用下列语句接受
SqlParameter sqlp = new SqlParameter("@sum",SqlDbType.Int);//对参数操作,所以用包含Paramter的语句
sqlp.Direction = ParameterDirection.Output;//direction为指向的意思,指向output
cmd.ExecuteNonQuery();//执行
}
//SqlDataAdapter函数应该怎样传递参数
DataTable dt = new DataTable();
string sql = "";
using (SqlDataAdapter sda=new SqlDataAdapter(sql,str))
{
//以下三个语句是将参数的添加到sda对象里面,并执行不同的操作
sda.SelectCommand.Parameters.Add("参数的值");//显示
sda.DeleteCommand.Parameters.Add("参数的值");//删除
sda.UpdateCommand.Parameters.Add("参数的值");//更新
sda.Fill(dt);
}