【问题标题】:How to save a half-completed form如何保存半完成的表格
【发布时间】:2010-11-16 04:45:10
【问题描述】:

我正在开展一个项目,我们希望让用户能够保存他们完成一半的表单,以便他们以后可以回来完成它。我正在努力弄清楚我想如何做到这一点。我是否将它们与已完成的应用程序保存在同一个池中,仅具有特殊状态?我真的不想牺牲已完成的应用程序的完整性,因为当我不希望它们为空时必须使它们为空。

我应该在不同的架构中创建相同的数据库结构来保存不完整的应用程序吗?我可以让这个其他模式在数据库约束和可空字段上更加宽松,以解决不完整的应用程序。

有没有更简单的方法来做到这一点?有没有办法可以保存视图状态并在以后恢复它?

感谢您的建议!

【问题讨论】:

    标签: asp.net architecture


    【解决方案1】:

    我肯定会把它保存到数据库中。您以特殊状态保存的计划(名为 Complete 的布尔标志会起作用)。然后你可以创建一个视图,它只提取 Complete = true 的项目,称为 CompletedApplications。

    【讨论】:

      【解决方案2】:

      您已完成的申请与这些“半”状态之间可能存在一些差异:

      1. 正如您所说,大多数验证都不合适,字段将为空,可能无法执行交叉验证。
      2. 您可能不需要对数据进行任意搜索。

      所以我会使用不同的数据库,记录包含几个关键字段,例如用户 ID、日期、他们填写的表单类型等,以及一个 blob他们填写的字段。我是一个 Java 人,所以我不知道 .NET 获取 blob 的方法,但在 Java 中我可以序列化支持表单的数据对象。

      在 C# 中,这些技术似乎与 Java 有一些相似之处,至少我对 article 的理解是正确的。

      我认为,如果不存在标准的 .Net 技术,手工制作一些简单的“saveAsAString”和“readFromString”代码会有点乏味但相当可行。

      【讨论】:

      • 我认为这是我想采取的方法,但序列化部分是我需要帮助的部分。
      • 添加了对似乎是相关文章的引用,如果没有人在这里插话,也许会问第二个关于序列化技术的问题。
      【解决方案3】:

      您显然无法将其保存到实际的数据表中,因此我将创建一个具有用户 ID、格式和二进制数据类型的单独表。将表单组合成一些可序列化的结构并序列化到数据库。当用户回来时,您可以反序列化并恢复表单状态。

      【讨论】:

      • 你能提供任何关于序列化网络表单的指导吗?它是一个带有向导控件的页面,其中包含多个步骤。
      • 我同意有一个序列化的 LOB——这意味着你不必在数据库中有很多可以为空的列。可以保存在数据库中,但我不建议这样做。 @MikeC-您不会序列化 Webform,而是序列化它所绑定的域模型。
      【解决方案4】:

      我也遇到过同样的问题。一个区别是我的方法涉及 ajax 自动保存,类似于您在 Gmail 和 Blogger 中看到的。但这不应该改变实现,真的。

      问题是我不想保存到通常的表格中,因为那需要验证(验证整数、货币、日期等)。而且我不想在用户真的想离开时唠叨他们。

      我最终想出了一个名为 AjaxSavedData 的表。它是数据库中的永久表,但它包含的数据往往是临时的。换句话说,它将暂时存储用户的数据,直到他们真正完成页面并进入下一个页面。

      该表仅由几列组成:

      AjaxSavedDataID - 整数:

      主键。

      用户 ID - 整数:

      识别用户(很简单)。

      页面名称 - varchar(100):

      如果您要处理多个页面,则需要。

      ControlID - varchar(100):

      我将其称为 ControlID,但它实际上只是 .NET 为所有 WebControl 公开的 ClientID 属性。因此,例如,如果 txtEmail 在名为 Contact 的用户控件中,则 ClientID 将是 Contact_txtEmail。

      - varchar(MAX):

      用户为给定字段或控件输入的值。

      DateChanged - 日期时间:

      添加或修改值的日期。

      除了一些自定义控件外,该系统还可以让所有这些都轻松“正常工作”。在我们的网站上,每个文本框、下拉列表、单选按钮列表等的 ClientID 保证对于给定页面是唯一且一致的。所以我能够编写所有这些,以便自动检索保存的数据。换句话说,我不必每次向表单添加一些字段时都连接此功能。

      此自动保存功能将进入 techinsurance.com 上一个非常动态的在线商业保险应用程序,使其更加用户友好。

      如果您有兴趣,这里是允许自动保存的 Javascript:

      function getNewHTTPObject() {
          var xmlhttp;
      
          /** Special IE only code */
          /*@cc_on
          @if (@_jscript_version >= 5)
          try {
              xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
          }
          catch (e) {
              try {
                  xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
              }
              catch (E) {
                  xmlhttp = false;
              }
          }
          @else
              xmlhttp = false;
          @end
          @*/
      
          /** Every other browser on the planet */
          if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
              try {
                  xmlhttp = new XMLHttpRequest();
              }
              catch (e) {
                  xmlhttp = false;
              }
          }
      
          return xmlhttp;
      }
      
      function AjaxSend(url, myfunction) {
          var xmlHttp = getNewHTTPObject();
          url = url + "&_did=" + Date();
          xmlHttp.open("GET", url, true);
          var requestTimer = setTimeout(function() { xmlHttp.abort(); }, 2000);
          xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
          xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2005 00:00:00 GMT");
          xmlHttp.onreadystatechange = function() {
              if (xmlHttp.readyState != 4)
                  return;
              var result = xmlHttp.responseText;
              myfunction(result);
          };
          xmlHttp.send(null);
      }
      
      // Autosave functions
      var SaveQueue = []; // contains id's to the DOM object where the value can be found
      var SaveQueueID = []; // contains id's for binding references (not always the same)
      
      function ArrayContains(arr, value) {
          for (i = 0; i < arr.length; i++) {
              if (arr[i] == value)
                  return true;
          }
      
          return false;
      }
      
      function GetShortTime() {
          var a_p = "";
          var d = new Date();
          var curr_hour = d.getHours();
      
          if (curr_hour < 12)
              a_p = "AM";
          else
              a_p = "PM";
      
          if (curr_hour == 0)
              curr_hour = 12;
          else if (curr_hour > 12)
              curr_hour = curr_hour - 12;
      
          var curr_min = d.getMinutes();
          curr_min = curr_min + "";
      
          if (curr_min.length == 1)
              curr_min = "0" + curr_min;
      
          return curr_hour + ":" + curr_min + " " + a_p;
      }
      
      function Saved(result) {
          if (result == "OK") {
              document.getElementById("divAutoSaved").innerHTML = "Application auto-saved at " + GetShortTime();
              document.getElementById("divAutoSaved").style.display = "";
          }
          else {
              document.getElementById("divAutoSaved").innerHTML = result;
              document.getElementById("divAutoSaved").style.display = "";
          }
      }
      
      function getQueryString(name, defaultValue) {
          var query = window.location.search.substring(1);
          var vars = query.split("&");
          for (var i = 0; i < vars.length; i++) {
              var pair = vars[i].split("=");
              if (pair[0] == name) {
                  return pair[1];
              }
          }
      
          return defaultValue;
      }
      
      function urlencode(str) {
          return escape(str).replace(/\+/g, '%2B').replace(/%20/g, '+').replace(/\*/g, '%2A').replace(/\//g, '%2F').replace(/@/g, '%40');
      }
      
      function AutoSave() {
          if (SaveQueue.length > 0) {
              var url = "/AjaxAutoSave.aspx?step=" + getQueryString("step", "ContactInformation");
      
              for (i = 0; i < SaveQueue.length; i++) {
                  switch (document.getElementById(SaveQueue[i]).type) {
                      case "radio":
                          if (document.getElementById(SaveQueue[i]).checked)
                              url += "&" + SaveQueueID[i] + "=" + urlencode(document.getElementById(SaveQueue[i]).value);
                          break;
                      case "checkbox":
                          if (document.getElementById(SaveQueue[i]).checked)
                              url += "&" + SaveQueueID[i] + "=" + urlencode(document.getElementById(SaveQueue[i]).value);
                      default:
                          url += "&" + SaveQueueID[i] + "=" + urlencode(document.getElementById(SaveQueue[i]).value);
                  }
              }
      
              SaveQueue = [];
              SaveQueueID = [];
              AjaxSend(url, Saved);
          }
      }
      
      function AddToQueue(elem, id) {
          if (id == null || id.length == 0)
              id = elem.id;
      
          if (!ArrayContains(SaveQueueID, id)) {
              SaveQueue[SaveQueue.length] = elem.id;
              SaveQueueID[SaveQueueID.length] = id;
          }
      }
      

      将此添加到您的页面以使其正常工作:

      window.setInterval("AutoSave()", 5000);
      

      要将其应用于文本框、下拉列表、列表框或复选框,您只需添加此属性:

      onchange="AddToQueue(this)"
      

      ...或者这个用于 RadioButtonList 或 CheckBoxList:

      onchange="AddToQueue(this, '" + this.ClientID + "')"
      

      【讨论】:

      • 那么当您保存控件时,您是否只是遍历 Controls 集合?
      • 实际上,由于它是基于 ajax 的解决方案,因此通过 Javascript 以每次更改为基础进行保存。我在检测用户所做的任何更改并将这些更改添加到数组的所有字段上都有 Javascript onchange 事件。然后我有一个 setInterval 调用,它清空数组并每 5 秒通过 ajax 将所有这些更改发送到一个单独的 aspx 页面。这样,它只会更新已更改的内容,而不会更新其他内容,从而充分利用带宽。
      • 顺便说一下,所有这些 AJAX 东西都是完全自定义的。我什至懒得尝试使用 .NET 的 AJAX 东西,因为它让我很困惑。
      【解决方案5】:

      有没有想过使用 Silverlight? Silverlight 有独立存储,我见过几个例子,开发人员使用独立存储来存储昂贵的客户端数据。

      http://pietschsoft.com/post/2008/10/Silverlight-Client-Side-Database-via-LINQ-and-Isolated-Storage.aspx

      然后用js把数据取出来:

      http://msdn.microsoft.com/en-us/library/cc221414%28VS.95%29.aspx

      这使您无需任何额外的数据库空间,因为所有用户的临时表单条目都存储在独立存储中,当他们返回页面时,您会询问用户是否要继续编辑...然后填充表单将数据存储在隔离存储中...

      听起来比添加新数据库更优雅?

      有一个缺点是依赖于机器的解决方案。

      取决于保存部分表单的确切目标? 是不是可以在其他机器上调出来?如果是这样,这不是正确的解决方案,数据库保存是一个更好的邪恶。

      【讨论】:

      • Silverlight 不适用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 2014-07-23
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      相关资源
      最近更新 更多