ASP.NET MVC部分视图回发,不一致的更新和Bizzare行为

时间:2016-07-21 21:22:39

标签: ajax asp.net-mvc partial-views

我正在开发一个ASP.Net MVC应用程序,并且在尝试通过部分回发更新数据库中的数据时遇到了一个奇怪的问题。在HTTP,AJAX等方面,我还是新手,所以我希望这是一个明显的错误。

基本上,当我尝试更新将内容区域与评估相关联的表格时,更新有时会起作用,有时并不起作用。在我发布之后,我直接从MVC应用程序查询数据库只是为了确保实际做出了预期的更改(这就是所有的ViewBag) .DebugInfo正在做下面的代码)。在每种情况下,查询都会返回我希望看到的内容。但是当我通过SSMS 查询表时,我发现有时只会发生变化。

从我的MVC应用程序直接查询表是如何显示更新已经完成的,而我可以清楚地看到它没有通过SSMS?是否有静音回滚或什么?这令人抓狂,任何帮助都会非常感激。

一些信息:

  • 当我运行" saveTheData"函数来自MVC之外的下面的assessmentContent类,它总是成功的。
  • 第一篇文章的更新总是成功。
  • 此更新仅在后续帖子的一半时间内成功完成。
  • 当更新不成功时,来自MVC应用程序的直接查询检查似乎确实表明更新已经一直到达表。
  • 我几乎无法在失败中找出一个模式。也就是说,似乎每当我尝试更新到更高的contentId值时,它就会成功,如果我尝试更新到更低的contentId,则不是。例如,从值1(数学)更新为2(读数)将始终通过,但反过来不会。如果它是父视图中的第一个帖子,或者它是通过Linqpad更新的,则不会显示此模式。
  • 我在写入日志记录表的数据库表上放置了插入,更新和删除触发器,以查看是否正在回滚更改。但是日志表上的条目没有失败。但我也不知道回滚是否会撤消触发器。
  • 我查询dbo.fn_dblog()过滤了Operation =' LOP_ABORT_XACT',但没有(虽然我没有训练过那个困难视角的眼睛)。

这是我的课程,用于获取和更新数据:

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()可以命名为&#39; getAssessmentContent()&#39;。

这是我的部分视图控制器和一些相关代码:

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层架构或模型 - 视图 - 控制器结构。

你会注意到,在我的绝望中,我在模型的每个变化点直接检查数据库表。

部分视图:

@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>

2 个答案:

答案 0 :(得分:1)

您确定要对数据库进行的事务是已提交还是已完成?可能会同时进行其他交易,可以回滚您正在进行的交易。

答案 1 :(得分:1)

我讨厌一个问题,但没有完全确定我解决它的问题。但是在完成上面的一些代码之后,我得到了正确且一致的工作。

然而,我几乎可以肯定,这个问题与将数据从服务器传递到客户端以及返回时对asp.net mvc的工作方式的误解有关。也就是说,当我们将数据发送到客户端的html / asp时,我知道服务器上的C#viewmodels和控制器仍然存在。我预感到客户端数据与C#对象不同,但我确实觉得ASP.Net MVC正在更新C#对象,以便对回发进行任何更改。现在我很清楚,实际上C#对象被完全丢弃并完全实例化(调用构造函数和所有相关后果)并使用来自客户端的数据重新填充。即使客户没有进行任何更改,也是如此。

我认为更新实际上是对数据库进行的。没有发生回滚。但是在重新实例化时发生了一些事情,导致第二次调用数据库并重置其值。这可以解释为什么它在ASP.net MVC之外完美运行。这可以解释为什么我在实现之后解决了这个问题。

我会称此回复准确,但不准确。我的意思是,我有信心指导解决问题,即使它没有确定上面违反代码的确切行。由于准确性,我认为将其标记为答案是公平的游戏。由于不精确,我愿意将别人的回答标记为答案,如果他们可以更精确的话。但是,由于上面的代码已不再使用,因此只是出于学习目的。