目录
查询借书记录,并从图书表格调出书的具体信息,最后把这些东西合成一个表
comm.ExecuteScalar().ToString()报错
一、窗体转换
转到新窗体
可以关闭或隐藏原窗体
NewForm newForm = new NewForm();
newForm.Show();
this.Close();
//this.Hide();
回到旧窗体
前提是你没有关闭旧的窗体
//在新窗体定义一个字段保存旧窗体
private OldForm old;
// 在新窗体的构造函数中接收对旧窗体的引用
public NewForm(OldForm oldform)
{
this.old = oldform;
}
// 在新窗体中需要返回旧窗体时
private void ReturnToOldForm()
{
old.Show();
this.Hide();
//this.Close();
}
当然,这样的话新窗体的构造函数就变了,所以在旧窗体转换到新窗体的时候也需要做一点改变。
NewForm newForm = new NewForm(this); //把当前所在窗体传参进新窗体
newForm.Show();
this.Close();
//this.Hide();
二、数据库操作·脱机模式
查询一个数据
// 创建SqlConnection对象,连接用windows身份验证的SQL Server数据库
SqlConnection conn = new SqlConnection("Server = (local); Database = library; Trusted_Connection = yes");
// 打开与数据库的连接
conn.Open();
// 构造SQL查询语句,用于从userInfo表中查找具有指定NickName和Passwords的用户
string sql = "select count(*) from userInfo where NickName = " + LogName.Text + " and Passwords = " + LogCode;
// 创建SqlCommand对象,执行SQL查询语句
SqlCommand comm = new SqlCommand(sql, conn);
// 执行SQL查询语句,并返回查询结果(也就是用户数量)
int num = (int)comm.ExecuteScalar();
// 关闭与数据库的连接
conn.Close();
// 如果查询结果大于0,说明此用户存在
if (num > 0)
{
// 创建主窗体
MainForm mainForm = new MainForm();
mainForm.Show();
this.Close();
}
else
{
// 如果查询结果为0,说明没有找到匹配的用户,显示错误消息框
MessageBox.Show("用户名或密码错误,请重新输入或注册新账号", "提示");
}
新增或修改数据
//参数化查询避免sql注入风险
comm.CommandText = "insert into recordInfo (UserId, BookId, BorrowDate, Returned) values (@UserId, @BookId, @BorrowDate, 'no')";
comm.Parameters.AddWithValue("@UserId", log.userid);
comm.Parameters.AddWithValue("@BookId", bookid.Text);
comm.Parameters.AddWithValue("@BorrowDate", DateTime.Now);
查询多个数据
SqlConnection conn = new SqlConnection("Server=(local); Database=library; Trusted_Connection=yes");
conn.Open();
string sql = string.Format("select LTRIM(RTRIM(Admini)),LTRIM(RTRIM(UserId)) from userInfo where NickName = '{0}' and Passwords = '{1}'", LogName.Text, LogCode.Text);
SqlCommand comm = new SqlCommand(sql, conn);
//前面都一样,只是后面不太一样
// 创建一个新的SqlDataAdapter对象,用于执行SQL命令并填充DataTable。
SqlDataAdapter adapter = new SqlDataAdapter(comm);
// 创建一个新的DataTable对象,用于存储从数据库检索的数据。
DataTable dt = new DataTable();
// 使用SqlDataAdapter对象填充DataTable。
adapter.Fill(dt);
// 检查DataTable中是否有行。如果有,则执行下面的代码块。
if (dt.Rows.Count > 0)
{
// 从第一行第一列获取数据,并将其转换为字符串,然后赋值给变量adm。
adm = dt.Rows[0][0].ToString();
// 从第一行第二列获取数据,并将其转换为字符串,然后赋值给变量userid。
userid = dt.Rows[0][1].ToString();
}
三、限制输入的字符类型
常用函数
char c = (char)Console.Read();
//c是字母?
char.IsLetter(c);
//c是十进制数字?
char.IsDigit(c);
//c是字母或十进制数字?
char.IsLetterOrDigit(c);
如果是为了密码做限制功能
可以直接把UseSystemPasswordChar属性设置为true,方便省事
四、让tabcontrol的其中一个页面不可见
tabcontrol集合里的tabpage没有visible属性,要想隐藏的话,我试了以下几种方法。
方法一
//让这个page的父容器为空理论上它就不能在tabcontrol显示了
tPageBook.Parent = null;
//想要再显示就把parent属性改回去就行
方法二
//直接把页面删掉
tCtr.TabPages.Remove(tPageBook);
方法三
//隐藏并移除
tCtr.TabPages["tPageBook"].Dispose();
但是由于一些其他的错误,我试了半天也没成功,所以我放弃了,换了个实现这种功能的思路。
比如把界面的入口设置为一个button,只要隐藏button这个页面就也被隐藏了。
最后虽然我发现了那个离谱错误,但是懒得改回去了,所以上述方法是否有效得大家自己尝试了。
五、一点sql语句
查询借书记录,并从图书表格调出书的具体信息,最后把这些东西合成一个表
select
-- 选择b.BookId字段,即从子查询中获取图书ID,下面四句差不多
b.BookId,
b.BookName,
b.Genre,
b.Author,
b.Publisher,
BorrowDate,
ReturnDate,
Returned
-- 创建一个子查询,并命名为subquery_borrow。该子查询从recordInfo表中选取BookId、BorrowDate、ReturnDate和Returned字段。
from
(select BookId, BorrowDate,ReturnDate,Returned from recordInfo) as subquery_borrow
-- 使用JOIN操作将子查询subquery_borrow与bookInfo表连接。连接条件是两个表中的BookId字段相等。
JOIN
bookInfo as b on subquery_borrow.BookId = b.BookId;
六、出现的一些错误
1、System.Data.SqlClient.SqlException:“字符串或二进制数据将在表“library.dbo.userInfo”,列“Passwords”中被截断。截断值:“System.Windows.F”。
这是在执行插入数据的sql语句时出现的,大家都说这是字段长度超过了设置的长度,确实也是这样。
但我寻思我所有输入都有长度限制,怎么会出现这种错误呢,结果是我忘记写“.Text”了。。。
2、comm.ExecuteScalar().ToString()报错
如果 comm.ExecuteScalar()
返回 null,
直接调用 ToString()
方法会导致 NullReferenceException
异常,所以就报错了,可以像我这样改改:
//原代码
string str;
str = comm.ExecuteScalar().ToString();
//改正代码
string str;
object result = comm.ExecuteScalar();
if (result != null)
{
str = result.ToString();
}
3、查询结果比预期结果多空格,导致判断出错
代码:
//查询正在登录的用户是否是管理员
string sql = string.Format("select Admini from userInfo where NickName = '{0}' and Passwords = '{1}'", LogName.Text, LogCode.Text);
SqlCommand comm = new SqlCommand(sql, conn);
object result = comm.ExecuteScalar();
if (result != null)
{
adm = result.ToString();
}
如果用户不是管理员,结果应该是"no",但是我最终得到的adm是“no ”,这就导致了后续许多故障。
解决方案:
//去掉空格
string sql = string.Format("select LTRIM(RTRIM(Admini)) from userInfo where NickName = '{0}' and Passwords = '{1}'", LogName.Text, LogCode.Text);
4、线程间操作无效: 从不是创建控件“pnborr”的线程访问它。
//原代码,在关闭窗体的时候显示另一个窗体
private void BorrowRecord_FormClosed(object sender, FormClosedEventArgs e)
{
main.Show();
this.Close();
}
//改好的代码
private void BorrowRecord_FormClosed(object sender, FormClosedEventArgs e)
{
main.Show();
}
这个问题就在于,我已经在调用关闭函数了,但是我又在里面写了this.close(),无限套娃了。
5、System.Data.SqlClient.SqlException:“变量名 '@UserId' 已声明。
/*这是报错的代码,写在一个函数里,但是由于我的comm是全局变量,
所以第二次调用的时候就会报错说变量已声明*/
comm.Parameters.AddWithValue("@UserId", log.userid);
comm.Parameters.AddWithValue("@BookId", bookid.Text);
comm.Parameters.AddWithValue("@BorrowDate", DateTime.Now);
//只要在代码前面加上下面这句就可以解决了
comm.Parameters.Clear();
//也就是在每次声明变量前把已有的变量都清除
6、datagridview更新失败
错误代码:
string sele = bookcb.SelectedItem.ToString().Substring(1,2);
string found = booktb.Text;
//创建新表储存数据
DataTable bookdt1 = new DataTable();
//bookdt是我本来的数据源
foreach (DataRow row in bookdt.Rows)
{
if (row[sele].ToString().Trim() == found)
{
bookdt1.ImportRow(row);
}
}
if (bookdt1.Rows.Count > 0)
{
dgviewbook.DataSource = bookdt1;
dgviewbook.Refresh();
}
错误原因应该是我这个新表只有行数据,但是没有列结构,所以我选择在填充bookdt的时候填出一个一模一样的bookdt1。
更正后代码:
//填充数据
SqlDataAdapter adapter = new SqlDataAdapter(comm);
adapter.Fill(bookdt);
adapter.Fill(bookdt1);
//新代码
string sele = bookcb.SelectedItem.ToString().Substring(1,2);
string found = booktb.Text;
bookdt1.Rows.Clear();
foreach (DataRow row in bookdt.Rows)
{
if (row[sele].ToString().Trim() == found)
{
bookdt1.ImportRow(row);
}
}
if (bookdt1.Rows.Count > 0)
{
dgviewbook.DataSource = bookdt1;
dgviewbook.Refresh();
}
七、杂记(大部分是属性)
1、给label里的文字加下划线
属性font里
2、限制输入长度
MaxLength属性
3、combobox如果没有选中值
- ComboBox的SelectedIndex属性值为-1,表示未选中任何项。
- ComboBox的SelectedItem属性值为null。
- ComboBox的SelectedValue属性值为null。
4、datagridview的字体格式
列标题字体格式在ColumnHeadersDefaultCellStyle属性
单元格字体格式在DefaultCellStyle属性
5、把某些控件设置为半透明
//前面三个数值分别是红绿蓝色值
gbSetBook.BackColor = Color.FromArgb(168, 245, 243, 220);
//最后一个数220代表透明度,范围从完全透明(0)到完全不透明(255)
最后
ai还是挺好用的,至少写注释非常清晰,我浅改一下就可以了,妈妈再也不用担心我以后看不懂自己的代码啦。
这篇笔记是边写实验边记的,有什么记什么,所以很凌乱,写完实验如果我有时间可能会再重写一篇。