这段代码使用了 C# 的 字符串插值($) 和 逐字字符串(@) 功能,并在 SQL 语句中动态拼接变量。下面详细解释它们的用法:
1. $(字符串插值)
$ 是 C# 的 字符串插值 符号,允许在字符串中直接嵌入表达式(用 {} 包裹),例如:
string name = "Alice";
string message = $"Hello, {name}!"; // 输出:Hello, Alice!
在 SQL 语句中,$ 用于动态插入变量值,如 {level}、{GetNextSortOrder(parentId)} 等。
2. @(逐字字符串)
@ 是 C# 的 逐字字符串 符号,它会:
- 忽略转义字符(如
\n、\t等) - 允许字符串跨多行(适合 SQL 语句)
- 保留所有空格和换行
例如:
string sql = @"SELECT *FROM UsersWHERE Id = 1";
如果不加 @,换行符需要用 \n 表示,而加了 @ 后可以直接换行。
3. $@(同时使用)
$@ 结合了两种功能:
@允许 SQL 语句跨多行$允许在字符串中插入变量
所以:
string strsql = $@"INSERT INTO System (PID, Level, SortOrder, Name, remark, CreatedTime, ModifiedTime)VALUES (...)
";
这样既保持了 SQL 语句的可读性,又能动态插入变量。
4. {(level == 3 ? $"'{editForm.Target.Replace("'", "''")}'" : "NULL")} 解释
这段代码是一个 嵌套的三元运算符 + 字符串插值,用于动态生成 SQL 语句中的 remark 字段值:
level == 3:检查当前节点是否是第 3 级(可能是菜单项)- 如果是,则:
editForm.remark.Replace("'", "''"):对remark字符串进行 SQL 转义(单引号'替换成'',防止 SQL 注入)$"'{...}'":用单引号包裹(因为 SQL 字符串需要用'括起来)
- 如果不是(
level != 3),则直接插入NULL(SQL 的 NULL 值,不加引号)
- 如果是,则:
示例
假设:
level = 3editForm.remark= "admin/home"
则生成的 SQL 部分:
remark= 'admin/home'
如果 level = 2,则:
remark= NULL
5. 完整 SQL 拼接示例
假设:
parentId = 1level = 3editForm.NodeName = "Admin Page"editForm.remark = "admin/home"
生成的 SQL 语句:
INSERT INTO System
(PID, Level, SortOrder, Name, remark, CreatedTime, ModifiedTime)
VALUES (1,3,1, -- 假设 GetNextSortOrder(parentId) 返回 1'Admin Page','admin/home',GETDATE(),GETDATE()
)
6. 安全性注意事项
虽然这种拼接方式方便,但存在 SQL 注入风险(如果 NodeName、Target 等来自用户输入)。更安全的方式是使用 参数化查询(如 SqlCommand.Parameters):
using (var cmd = new SqlCommand(@"INSERT INTO System (PID, Level, SortOrder, Name, remark, CreatedTime, ModifiedTime)VALUES (@PID, @Level, @SortOrder, @Name, @remark, GETDATE(), GETDATE())", connection))
{cmd.Parameters.AddWithValue("@PID", parentId ?? (object)DBNull.Value);cmd.Parameters.AddWithValue("@Level", level);cmd.Parameters.AddWithValue("@SortOrder", GetNextSortOrder(parentId));cmd.Parameters.AddWithValue("@Name", editForm.NodeName);cmd.Parameters.AddWithValue("@remark", level == 3 ? editForm.Target : (object)DBNull.Value);cmd.ExecuteNonQuery();
}
这样可以有效防止 SQL 注入攻击。