如何通过ID从列表获取列数据,实现删除操作日志记录?
如何正确检索数据并完成删除日志的插入操作?
你的代码目前存在几个关键问题:循环内重复查询数据库、SQL语句拼接的风险,以及数据检索方式错误导致无法拿到正确值。我来帮你一步步修正:
1. 优化数据查询:一次性获取所有需要的记录
你现在在foreach循环里每次只查询一个ID对应的记录,这会触发多次数据库请求,效率极低。我们可以一次性把所有目标ID对应的Class记录拉取出来:
var targetRecords = context.Class .Where(details => ids.Contains(details.ID)) .Select(details => new { details.studNumber, details.name, details.lastName }) .ToList();
这样只需要一次数据库调用,就能拿到所有需要的学生数据,比循环查询高效太多。
2. 避免直接拼接SQL(风险+数据错误)
你当前拼接SQL的方式不仅有严重的SQL注入风险,而且result.Where(...)返回的是一个集合,直接拼到字符串里只会输出类型名称(比如System.Linq.Enumerable+WhereSelectListIterator...),根本拿不到实际的字段值。
推荐用EF的实体操作来插入日志,既安全又符合ORM的设计思路:
首先确保你有对应DeletedStudents表的实体类:
public class DeletedStudent { public string studNumber { get; set; } public string name { get; set; } public string lastName { get; set; } public string DeletedBy { get; set; } public DateTime DeletedOn { get; set; } public int stage { get; set; } }
然后修改你的方法:
public static void DeleteFromClass(this Entities context, List<long> ids, string deletedBy) { if (!ids.Any()) return; // 批量获取待删除学生的信息 var targetRecords = context.Class .Where(d => ids.Contains(d.ID)) .Select(d => new { d.studNumber, d.name, d.lastName }) .ToList(); // 转换为删除日志实体 var deletedLogs = targetRecords.Select(record => new DeletedStudent { studNumber = record.studNumber, name = record.name, lastName = record.lastName, DeletedBy = deletedBy, DeletedOn = DateTime.Now, stage = 1 }).ToList(); // 批量插入日志 context.DeletedStudents.AddRange(deletedLogs); context.SaveChanges(); // 执行原表的删除操作(你的原代码遗漏了这一步) var itemsToDelete = context.Class.Where(d => ids.Contains(d.ID)); context.Class.RemoveRange(itemsToDelete); context.SaveChanges(); }
3. 如果必须用SQL语句:使用参数化查询
如果因为特殊需求必须直接写SQL,一定要用参数化查询来避免注入,同时正确获取字段值:
public static void DeleteFromClass(this Entities context, List<long> ids, string deletedBy) { if (!ids.Any()) return; var targetRecords = context.Class .Where(d => ids.Contains(d.ID)) .Select(d => new { d.studNumber, d.name, d.lastName }) .ToList(); foreach (var record in targetRecords) { var insertSql = @"INSERT INTO DeletedStudents (studNumber, name, lastName, DeletedBy, DeletedOn, stage) VALUES (@studNumber, @name, @lastName, @deletedBy, @deletedOn, 1)"; // 用参数化执行,避免注入,同时确保值正确 context.Database.ExecuteSqlRaw(insertSql, new SqlParameter("@studNumber", record.studNumber), new SqlParameter("@name", record.name), new SqlParameter("@lastName", record.lastName), new SqlParameter("@deletedBy", deletedBy), new SqlParameter("@deletedOn", DateTime.Now)); } // 删除原表记录 var itemsToDelete = context.Class.Where(d => ids.Contains(d.ID)); context.Class.RemoveRange(itemsToDelete); context.SaveChanges(); }
核心问题总结
- 你原代码中
result.Where(e => e.id == item).Select(...)返回的是集合而非单个值,所以无法拿到正确的字段内容,直接取record.studNumber这类单个属性才是正确的方式。 - 循环内多次查询数据库是低效的,批量查询才是最优解。
- 直接拼接SQL存在注入风险,参数化查询或EF实体操作才是安全的做法。
内容的提问来源于stack exchange,提问作者MxsterClxkes




