C# WPF SQL查询绑定DataGrid抛出NullReferenceException异常
问题根因
你碰到的NullReferenceException本质是DataGrid绑定的数据源类型变了,硬转类型失败返回null,直接访问null的属性自然报错:
- 用
db.Issue_Note.ToList()绑定时,每一行的数据源都是强类型Issue_Note实体,SelectedItem as Issue_Note转换正常,所以不会出问题 - 点搜索之后你绑定的是
DataTable.DefaultView,这时候SelectedItem实际是DataRowView类型,根本不是Issue_Note,as转换直接返回null - 你构造函数里虽然写了SqlQuery的绑定代码,但下一行马上又用
db.Issue_Note.ToList()覆盖了,所以初始化阶段不会报错,只要执行过搜索就会触发异常
修复方案
1. 兼容两种数据源类型的取值逻辑
修改LoadGrid方法,不要硬转Issue_Note,先判空再根据实际数据源类型取出库单号:
public void LoadGrid() { dt = new DataTable(); string isnNo = string.Empty; // 先处理未选中行的边界情况 if (PnlISNDetails_SK.datagrid.SelectedItem == null) { MessageBox.Show("请先选择一条出库单记录"); return; } // 分别适配强类型实体和DataTable两种数据源 if (PnlISNDetails_SK.datagrid.SelectedItem is Issue_Note noteEntity) { isnNo = noteEntity.Issue_No; } else if (PnlISNDetails_SK.datagrid.SelectedItem is DataRowView rowView) { isnNo = rowView["Issue_No"].ToString(); } if (string.IsNullOrWhiteSpace(isnNo)) { MessageBox.Show("未获取到选中的出库单号"); return; } addIssueNoteLogic = new AddIssueNoteLogic(); addIssueNoteLogic.ViewISNDetails(isnNo).Fill(dt); dgItemsInISN.ItemsSource = dt.DefaultView; }
2. 修复EF原生SQL查询的映射问题
如果要继续用SqlQuery<Issue_Note>返回强类型实体,要满足两个要求:
- 查询返回的列名必须和
Issue_Note实体的属性名完全匹配,大小写、拼写不能有偏差 - 必须查询实体标注的主键列,否则EF实体跟踪逻辑会异常,容易出现属性值为null的问题
- 构造函数里重复给
ItemsSource赋值的冗余代码删掉,只保留需要的绑定逻辑即可
如果不想兼容两种数据源,做筛选时完全可以不用SqlDataAdapter填DataTable,直接用EF的参数化Where查询或者SqlQuery返回List<Issue_Note>绑定,全程用强类型实体,从根源上避免类型转换问题。
3. 必须修复SQL注入漏洞
你现在直接拼接用户输入到SQL语句的写法有严重的SQL注入风险,必须改成参数化查询,以按单号查询为例:
public SqlDataAdapter ViewISNFromISNNo(string searchText) { con.Open(); cmd = new SqlCommand(); // 不要直接拼接searchText,用参数占位 cmd.CommandText = "select * from Issue_Note where Issue_No like @searchKey"; // 给参数传值 cmd.Parameters.AddWithValue("@searchKey", $"%{searchText}%"); cmd.Connection = con; da = new SqlDataAdapter(cmd); con.Close(); return da; }
其余按日期查询、查明细的方法都按这个逻辑改成参数化,不要直接拼接字符串,否则不仅容易被SQL注入攻击,还会频繁出现日期格式不匹配、特殊字符转义失败的问题。
额外优化建议
- 数据库连接对象不要用全局共享实例,每次查询时新建
SqlConnection,用完自动释放,否则很容易出现连接池占满、连接状态异常的问题 - 所有实现了
IDisposable的对象(SqlConnection、SqlCommand、SqlDataAdapter等)都包裹在using块中,自动释放资源,避免内存泄漏
内容的提问来源于stack exchange,提问作者Tharindu
相关产品推荐
相关产品推荐

