所以我花了一些时间来研究检查记录是否存在的最佳方法。结束了这一点。
var checkExistance = "SELECT TOP 1 exerVariName FROM exerciseVariants WHERE exerVariName = '" + exerVariName + "'";
然而,在我的页面上使用它时,我多次失败才能完成这项工作!
var exerVariName = Request.Form["exerVariName"];
var checkExistance = "SELECT TOP 1 exerVariName FROM exerciseVariants WHERE exerVariName = '" + exerVariName + "'";
if (IsPost && Validation.IsValid()) {
if (ModelState.IsValid) {
foreach (var c in db.Query(checkExistance)) {
if (c.exerVariName != exerVariName) {
var insertData = "INSERT INTO exerciseVariants (exerVariName, exerVariNameID) " +
"VALUES (@0, @1)";
db.Execute(insertData, exerVariName, exerciseID);
Response.Redirect("~/insertexervariname");
}
}
}
}
所以我放入SQL行的变量是一个请求表单的东西,所以它是一个用户输入,我想检查它是否存在于数据库中,如果它已经存在我不希望它被发布。以上就是我尝试使用foreach
中的if ispost
。
如何实现这一目标? (c#razor / cshtml)
答案 0 :(得分:0)
您的代码有竞争条件。
执行所需操作的最佳方法是让数据库使用唯一索引/约束来强制执行约束:
create unique index unq_exerciseVariants_exerVariName on exerciseVariants(exerVariName);
如果您想避免更新错误,那么您也可以在更新时进行检查:
INSERT INTO exerciseVariants (exerVariName, exerVariNameID)
SELECT exerVariName, exerVariNameID
FROM (SELECT @0 as exerVariName, @1 as exerVariNameID
) x
WHERE NOT EXISTS (SELECT 1
FROM exerciseVariants
WHERE ev.exerVariName = x.exerVariName
);
请注意,如果两个不同的线程尝试同时插入相同的名称,则由于竞争条件,此检查可能不够。这就是为什么最好让数据库强制执行唯一性。
答案 1 :(得分:0)
我绝不是C#的人,但我确实看到了你当前代码的一个逻辑问题。目前,您的EXISTS
和INSERT
查询是分开运行的,由几行.NET代码分隔,可能还有更多实际的机器指令。网络(没有双关语)的结果是,当存在检查显示为真但不再为真时,您最终可能会插入。为避免这种情况,存在检查应出现在WHERE
的{{1}}子句中。这样的事情应该有效:
INSERT
现在INSERT INTO exerciseVariants (exerVariName, exerVariNameID)
VALUES (@0, @1)
WHERE EXISTS
(
SELECT * exerVariName
FROM exerciseVariants
WHERE exerVariName = '" + exerVariName + "'";
)
应该以原子方式发生,这意味着您的检查和实际插入都将同时完成,无论其他线程可能在做什么。