我正在开发一个 ASP.Net MVC 应用程序,在尝试通过部分回发更新数据库中的数据时遇到了一个奇怪的问题。对于 HTTP、AJAX 等我还是个新手,所以我希望这是一个明显的错误。
基本上,当我尝试更新将内容区域链接到评估的表格时,更新有时有效,有时无效。奇怪的是,在我发布后,我直接从 MVC 应用程序查询数据库,只是为了确保确实进行了预期的更改(这就是所有 ViewBag.DebugInfo 在下面的代码中所做的事情)。在每种情况下,查询都会返回我希望看到的内容。但是,当我通过 SSMS 查询表时,我发现更改只是有时会发生。
从我的 MVC 应用程序对表的直接查询显示更新已完成,而我可以清楚地看到它没有通过 SSMS 进行,这是怎么回事?有无静默回滚之类的吗?这令人抓狂,我们将不胜感激任何帮助。
一些信息:
- 当我在 MVC 之外从下面的assessmentContent 类运行“saveTheData”函数时,它总是成功的。
- 第一次发布时更新总是成功。
- 后续帖子的更新成功率只有大约一半。
- 当更新不成功时,来自 MVC 应用程序的直接查询检查似乎确实表明更新已完全到达表。
- 我几乎无法从失败中找出规律。也就是说,似乎每当我尝试更新到较高的 contentId 值时,都会成功,如果我尝试更新到较低的 contentId 值,则不会成功。例如,从值 1(数学)更新到 2(阅读)总是会成功,但反之则不会。如果它是来自父 View 的第一篇文章,或者如果它是通过 Linqpad 更新的,则此模式不会显现。
- 我在数据库表上放置了插入、更新和删除触发器,这些触发器写入日志记录表以查看更改是否正在回滚。但失败时日志表中没有任何条目。但我也不知道回滚是否也会撤消触发器。
- 我查询了 dbo.fn_dblog(),过滤了操作 = 'LOP_ABORT_XACT',但什么也没有(尽管我没有训练有素的眼睛来观察这个困难的 View )。
这是我的类,用于获取和更新数据:
public class assessmentContent {
public int? assessmentId { get; set; }
public List<short> baseline { get; set; } = new List<short>();
public List<short> comparison { get; set; } = new List<short>();
public assessmentContent() { if (assessmentId != null) refreshTheData(); }
public assessmentContent(int assessmentId) {
this.assessmentId = assessmentId;
refreshTheData();
}
public void saveTheData() {
List<short> upserts = comparison.Except(baseline).ToList();
List<short> deletes = baseline.Except(comparison).ToList();
foreach (var upsert in upserts)
reval.ach.addAssessmentContent(assessmentId, upsert);
foreach (var delete in deletes)
reval.ach.deleteAssessmentContent(assessmentId, delete);
refreshTheData();
}
void refreshTheData() {
baseline = reval.ach.assessmentContent(assessmentId).ToList();
comparison = reval.ach.assessmentContent(assessmentId).ToList();
}
}
当我在 MVC 应用程序之外使用它时,逻辑工作正常。因此,例如,如果我通过 linqpad 使用它,就没有问题。我应该提到assessmentContent() 可以命名为“getAssessmentContent()”。
这是我的部分 View Controller ,以及一些相关代码:
public class ContentsModel {
public int? assessmentId { get; set; }
public List<short> comparison { get; set; }
}
public class ContentsController : Controller {
public static string nl = System.Environment.NewLine;
public ActionResult ContentsView(int assessmentId) {
ViewBag.DebugInfo = new List<string>();
var vm = new ContentsModel();
vm.assessmentId = assessmentId;
vm.comparison = reval.ach.assessmentContent(assessmentId).ToList();
return View("~/Views/ach/Contents/ContentsView.cshtml", vm);
}
public ActionResult update(ContentsModel vm) {
ViewBag.DebugInfo = new List<string>();
sqlFetch();
ViewBag.DebugInfo.Add($"VM Pased In {vm.assessmentId} c{vm.comparison.intsJoin()}");
sqlFetch();
var crud = new crud.ach.assessmentContent((int)vm.assessmentId);
ViewBag.DebugInfo.Add($"newly fetched CRUD {crud.assessmentId} b{crud.baseline.intsJoin()} c{crud.comparison.intsJoin()}");
sqlFetch();
crud.comparison = vm.comparison;
ViewBag.DebugInfo.Add($"CRUD after crud_comparison = vm_comparison {crud.assessmentId} b{crud.baseline.intsJoin()} c{crud.comparison.intsJoin()}");
sqlFetch();
crud.saveTheData();
ViewBag.DebugInfo.Add($"CRUD after save {crud.assessmentId} b{crud.baseline.intsJoin()} c{crud.comparison.intsJoin()}");
sqlFetch();
vm.comparison = crud.comparison;
ViewBag.DebugInfo.Add($"VM after vm_comparison = crud_comparison {vm.assessmentId} c{vm.comparison.intsJoin()}");
sqlFetch();
return PartialView("~/Views/ach/Contents/ContentsView.cshtml", vm);
}
void sqlFetch() {
ViewBag.DebugInfo.Add(
"SQL Fetch " +
Sql.ExecuteOneColumn<short>("select contentId from ach.assessmentContent where assessmentId = 12", connections.research).intsJoin()
);
}
}
public static partial class extensions {
public static string intsJoin(this IEnumerable<short> ints) {
var strings = new List<string>();
foreach (int i in ints)
strings.Add(i.ToString());
return string.Join(",", strings);
}
}
我知道我可能没有在这里最好实现的 3 层架构或模型- View - Controller 结构。
您会注意到,在我的绝望中,我在模型的每个更改点都直接检查数据库表。
部分 View :
@model reval.Views.ach.Contents.ContentsModel
@using reval
@{Layout = "";}
<div id="contentDiv">
<form id="contentForm">
@Html.HiddenFor(m => m.assessmentId)
@Html.ListBoxFor(
m => m.comparison,
new reval.ach.content()
.GetEnumInfo()
.toMultiSelectList(
v => v.Value,
d => d.DisplayName ?? d.Description ?? d.Name,
s => Model.comparison.Contains((short)s.Value)
),
new { id = "contentListBox" }
)
</form>
<br/>
@foreach(string di in ViewBag.DebugInfo) {
@Html.Label(di)
<br/>
}
</div>
<script>
$("#contentListBox").change(function () {
$.ajax({
url: "/Contents/update",
type: "get",
data: $("#contentForm").serialize(),
success: function (result) {
$("#contentDiv").html(result);
},
error: function (request, status, error) {
var wnd = window.open("about:blank", "", "_blank");
wnd.document.write(request.responseText);
}
});
})
</script>
最后,来自主视图的调用:
<div id="testDiv">
@if (Model.assessment != null && Model.assessment.assessmentId != null) {
Html.RenderAction("ContentsView", "Contents", new { assessmentId = Model.assessment.assessmentId });
}
</div>
最佳答案
您确定对数据库进行的事务已提交或完成吗?可能有其他事务同时进行,这些事务可能会回滚您正在进行的事务。
关于ajax - ASP.NET MVC 部分 View 回发、不一致的更新和奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38514580/