一、带参数的Sql语句(避免注入攻击)
(一) 注入漏洞攻击
在用户名中输入:jk’ or 1=1 --
select count(*) from UserLogin where loginId=’jk’ or 1=1 --‘ and Loginpwd=’jk1324657’
(二) 带参数的Sql语句
--@uid不用单引号引起来
string sql = “select count(*) from UserLogin where LoginId=@uid and LoginPwd=@pwd”;
using(SqlCommand cmd = new SqlCommand(sql,con))
{
cmd.Parameters.AddWithValue(“@uid”,txtUid.Text.Trim()uidParameters.AddWithValue()nd()d and LoginPwd=@pwdId);
cmd.Parameters.AddWithValue(“@pwd”,txtPwd.Text uidParameters.AddWithValue()nd()d and LoginPwd=@pwdId);
}
在数据库中,两个’’表示一个’
二、数据库与文本文件导入导出
(一) 数据库导出到文件
//需要创建一个写入文件的文件流StreamWriter
using(StreamWriter sw = new StreamWriter(@”tblclass.txt”))
{
while(reader.Read())
{
object objClsId = reader.GetValue(0);
object objClsName = reader.GetValue(1);
object objClsDesc = reader.GetValue(2);
string line = string.Format(“{0},{1},{2}”, objClsId, objClsName, objClsDesc);
sw.WriteLine(line);
}
}
(二) 文件导入到数据库
防止参数重名:
1、 方法一:
while(!sr.EndOfStream)
{
string line = sr.ReadLine();
string[] columns=line.Split(‘,’);
SqlParameter p1 = new SqlParameter(“@clsName”,columns[1]);
SqlParameter p2 = new SqlParameter(“@clsDesc”,columns[2]);
cmd.Parameter.Add(p1);
cmd.Parameter.Add(p2);
cmd.ExecuteNonQuery();
//每次用完参数,将参数集合清空。
cmd.Parameter.Clear();
}
2、 方法二:
SqlParameter p1 = new SqlParameter(“@clsName”,SqlDbType.VarChar);
SqlParameter p2 = new SqlParameter(“@ClsDesc”,SqlDbType.VarChar);
cmd.Parameter.Add(p1);
cmd.Parameter.Add(p2);
con.Open();
while(!sr.EndOfStream)
{
string line = sr.ReadLine();
string[] columns = line.Split(‘,’);
p1.Value = Columns[1];
p2.Value = Columns[2];
cmd.ExecuteNonquery();
}
(三) 省市联动案例
//获取配置文件中的连接字符串
string constr = ConfigurationManager.ConnectionString[0].ConnectionString;
//建议编写实体类的时候用属性,不用字段,因为很多控件不支持字段。
(四) 资料管理器(数据库版)
1、//窗体加载事件
Form_Load()
{
//加载文章类别到treeview
}
//实际开发应避免使用DataReader,用List集合
LoadCategoryToTree()
{
连接字符串
using(con)
{
sql = “select tid,tname from Category where tParentId = -1”;
…
categoryId = reader.GetInt32(0);
categoryName = reader.GetString(1);
//将当前类别加载到TreeView上
TreeNode tnode = treeview1.Add(categoryName);
tnode.Tag = categoryId;
//加载当前类(categoryId)下的所有子类
LoadSubCategory(categoryId,tnode)
}
}
//该方法创建一个新的连接,因为上一个方法的连接还没有关闭。
LoadSubCategory()
{
…
TreeNode subTNode = tnode.Nodes.Add(CategoryName);
}
//选中类别改变后的事件
treeView1_AfterSelect(object sender,TreeViewEventArgs e)
{
//e.Node表示当前选中的节点
if(e.Node.Level == 1)//选中2级节点
{
object categoryId = e.Node.Tag;
//根据类别Id(categoryId)加载文章到ListBox
LoadContentInfo(categoryId);
}
}
//在ListBox中加载文章标题
LoadContentInfo()
{
listBox1.Items.clear();
sql = “select did,dname from ContentInfo where dtid = @cateId”;
…
listBox1.Items.Add(wz);
}
//文章标题选择项改变事件
listBox1_SelectedIndexChanged()
{
if(listBox1.SelectedItem != null)
{
//根据文章Id,查询文章内容
GetArticleContentById();
}
}
GetArticleContentById()
{
string sql = “select dcontent from ContectInfo where dId=@id”;
cmd.Parameters.AddWithValue()
object objContent = cmd.ExecuteScalar();
return objContent.ToString();
}
2、 写配置文件(连接字符串)
<configuration>
<connectionStrings>
<add name=”sql” connectionString=”Data Source=.\SQLEXPRESS”/>
</connectionStrings>
</configuration>
3、 建立WenZhang类
三、DataSet (ado.net断开式数据访问)
DataSet是什么?临时数据集…
(一) 自己写DataSet
//1、创建一个临时数据库
DataSet ds = new DataSet(“School”);
//2、创建临时表
DataTable dt = new DataTable(“Student”);
//2.1为dt加列
DataColumn dcAutoId = new DataColumn(“autoId”);
dcAutoId.AutoIncrement = true;
dt.Columns.Add(“loginId”);
dt.Columns.Add(“loginId”,typeof(string));
dt.Columns[0].Uinque = true; //唯一性
for()
{
2.2为DataTable增加行
//创建DataRow不能new
DataRow dr = dt.NewRow();
dr[1] = “zxh”;
dr[2] = “zxh1234567”;
dt.Rows.Add(dr);
}
循环遍历输出DataSet
foreach(DataTable)
{
cw(dtItem.TableName);
foreach(DataRow)
{
for(循环列)
{
}
cwl();
}
}
//3、将DataTable加到DataSet中
ds.Tables.Add(dt);
(二) 自动填充DataSet
//SqlDataAdapter内部封装了SqlConnection、SqlCommand、SqlDataReader
SqlDataAdapter adapter = new SqlDataAdapter(sql,constr);
DataSet ds = new DataSet();
adapter.Fill(ds);
dataGridView1.DataSource = ds.Tables[0];
数据多了使用SqlDataAdapter分页
DataTable dt = new DataTable();
adapter.Fill(0,10,dt);
dataGridView1.DataSource =dt;
四、SQLHelper
封装一个SQLHelper方便使用
1、 建配置文件
2、
public static class SqlHelper
{
//获取配置文件中的连接字符串
private static readonly string constr =ConfigurationManager.ConnectionStrings[“sql”].ConnectionString;
//封装ExecuteNonQuery
public static int ExecuteNonQuery(string sql,params SqlParameter[] pms)
{
using(SqlConnection con = new SqlConnection(constr))
{
using(SqlCommand cmd = new SqlCommand(sql,con))
{
//如果pms为null,则直接调用cmd.Parameters.AddRange(pms)会报错
if(pms!=null)
{
cmd.Parameters.AddRange(pms);
}
con.Open();
return cmd.ExecuteNonquery();
}
}
}
//封装ExecuteScalar
//封装ExecuteReader
//注意
1、 Connection不能关闭
2、 DataReader不能关闭
3、 command对象执行ExecuteReader()的时候需要传递一个参数
public static SqlDataReader ExecuteReader(string sql,params SqlParameter[] pms)
{
SqlConnection con = new SqlConnection(constr);
using(SqlCommand cmd = new SqlCommand(sql,con))
{
if(pms!=null)
{
cmd.Parameters.AddRange(pms);
}
con.Open();
//当调用ExecuteReader()方法的时候,如果传递一个CommandBehavior.CloseConnecton参数,则表示将来当用户关闭reader的时候,系统会自动将Connection也关闭掉
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
}
}
//封装一个返回DataTable的方法ExecuteDataTable()
}
以后在ADO.Net中检索数据库中的数据用:
App.comfig+SqlHelper+带参数的SQL语句
这里的参数的声明方法:
//这里不能用cmd.Parameter.Add()
SqlParameter[] pams = new SqlParameter[]{
new SqlParameter("@UserName",txtUserName),
new SqlParameter("@Password",txtPassword)
};
连接池可以在连接字符串中打开关闭
作业:P65登录错三次禁止
P67 练习
资源管理器(数据库版)右键增加子类别,删除类别
将类别导出到记事本
将记事本文件导入到当前类别下
CSV电话本
我的作业:
怎么用List集合取代DataSet?
把treeview搞懂!
问题:什么是存储过程?