如何用ASP.NET C#实现带唯一ID及多地址的人员数据库插入
问题分析与解决方案
现有代码核心问题
- SQL注入风险:直接拼接用户输入到SQL语句中,存在严重安全隐患
- 表关联逻辑错误:查询语句
SELECT pID, pname FROM addresses, persons WHERE addresses.pID = persons.pname关联条件错误,正确关联应为addresses.pID = persons.pID - 重复检查逻辑无效:用
TextBox1.Text == TextBox3.Text判断人员是否存在完全不符合业务逻辑 - 插入顺序错误:先插入地址再插入人员,此时地址关联的
pID可能不存在,会触发外键约束错误 - 资源管理不规范:未使用
using语句自动释放数据库连接,存在资源泄漏风险
步骤1:创建符合需求的数据库表结构
先建立人员主表与地址从表,通过外键实现一对多关联:
-- 人员表(主表) CREATE TABLE Persons ( pID INT PRIMARY KEY IDENTITY(1,1), -- 自增唯一主键ID pName NVARCHAR(50) NOT NULL, -- 可扩展其他字段:如phone, email等 ); -- 地址表(从表),外键关联人员表pID CREATE TABLE Addresses ( addressID INT PRIMARY KEY IDENTITY(1,1), address NVARCHAR(200) NOT NULL, pID INT NOT NULL, FOREIGN KEY (pID) REFERENCES Persons(pID) -- 建立外键约束,确保地址关联有效人员 );
步骤2:修正C#代码实现逻辑
核心逻辑:插入前检查人员是否存在,不存在则先插入人员再插地址;已存在则直接插入关联地址。同时使用参数化查询避免注入,规范资源管理:
using System; using System.Data.SqlClient; using System.Web.UI; using System.Web.UI.WebControls; namespace WebApplication1 { public partial class PersonsData : System.Web.UI.Page { // 提取连接字符串,便于维护 private readonly string _connString = "Data Source=(LocalDB)\\MSSQLLOCALDB;Initial Catalog=personsDB;Integrated Security=True"; protected void Page_Load(object sender, EventArgs e) { } protected void Button3_Click(object sender, EventArgs e) { // 基础输入验证 if (string.IsNullOrWhiteSpace(TextBox1.Text) || string.IsNullOrWhiteSpace(TextBox2.Text)) { ScriptManager.RegisterStartupScript(this, GetType(), "alert", "alert('请填写完整人员姓名和地址信息');", true); return; } int targetPersonId = 0; // 使用using自动释放连接资源 using (SqlConnection conn = new SqlConnection(_connString)) { conn.Open(); // 检查人员是否已存在(按姓名查询,若需按ID查询可修改条件) string checkPersonSql = "SELECT pID FROM Persons WHERE pName = @pName"; using (SqlCommand checkCmd = new SqlCommand(checkPersonSql, conn)) { checkCmd.Parameters.AddWithValue("@pName", TextBox1.Text); object queryResult = checkCmd.ExecuteScalar(); if (queryResult != null) { // 人员已存在,获取其ID targetPersonId = Convert.ToInt32(queryResult); } else { // 人员不存在,插入新人员并返回自增ID string insertPersonSql = "INSERT INTO Persons (pName) OUTPUT INSERTED.pID VALUES (@pName)"; using (SqlCommand insertPersonCmd = new SqlCommand(insertPersonSql, conn)) { insertPersonCmd.Parameters.AddWithValue("@pName", TextBox1.Text); targetPersonId = Convert.ToInt32(insertPersonCmd.ExecuteScalar()); } } } // 插入关联地址 string insertAddressSql = "INSERT INTO Addresses (address, pID) VALUES (@address, @pID)"; using (SqlCommand insertAddrCmd = new SqlCommand(insertAddressSql, conn)) { insertAddrCmd.Parameters.AddWithValue("@address", TextBox2.Text); insertAddrCmd.Parameters.AddWithValue("@pID", targetPersonId); insertAddrCmd.ExecuteNonQuery(); } conn.Close(); } // 操作反馈与清空输入 ScriptManager.RegisterStartupScript(this, GetType(), "success", "alert('数据插入成功');", true); TextBox1.Text = TextBox2.Text = TextBox3.Text = ""; } } }
关键改进说明
- 参数化查询:所有用户输入通过
SqlParameter传递,彻底规避SQL注入 - 正确的重复校验:通过数据库查询判断人员是否存在,符合业务逻辑
- 资源自动释放:
using语句自动释放连接、命令对象,避免资源泄漏 - 原子性保障(可选):若需确保人员与地址插入的原子性,可添加
SqlTransaction处理异常回滚 - 输入验证:提前校验输入完整性,提升用户体验
内容的提问来源于stack exchange,提问作者Elie
相关产品推荐
相关产品推荐

