如何保存半完成的表格

时间:2009-08-02 17:02:09

标签: asp.net architecture

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

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

有更简单的方法吗?有没有办法可以保存视图状态并在以后恢复它?

感谢您的任何建议!

5 个答案:

答案 0 :(得分:4)

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

麻烦的是我不想保存到通常的表中,因为这需要验证(验证整数,货币,日期等)。当他们真的只想离开时,我不想唠叨用户。

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

该表仅由几列组成:

AjaxSavedDataID - int:

主键。

UserID - int:

识别用户(足够简单)。

PageName - varchar(100):

如果您正在使用多个页面,那么这是必要的。

ControlID - varchar(100):

我称之为ControlID,但它实际上只是.NET为所有WebControl公开的ClientID属性。因此,如果例如txtEmail位于名为Contact的用户控件内,那么ClientID将是Contact_txtEmail。

- varchar(MAX):

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

DateChanged - datetime:

添加或修改值的日期。

除了一些自定义控件外,该系统还可以让所有这些操作“轻松工作”。在我们的网站上,每个文本框,下拉列表,radiobuttonlist等的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);

要将其应用于Textbox,DropdownList,Listbox或Checkbox,您只需添加此属性:

onchange="AddToQueue(this)"

...或者这对于RadioButtonList或CheckBoxList:

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

答案 1 :(得分:3)

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

答案 2 :(得分:1)

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

  1. 如你所说,大多数验证都不合适,字段为空,可能无法执行交叉验证。
  2. 您可能不需要跨数据的任意搜索功能。
  3. 所以我会使用一个不同的数据库,记录包含一些关键字段,例如用户ID,日期,填写表格的类型等,以及 blob 他们填补的领域。我是一个Java人,因此我不知道.NET获取blob的方法,但在Java中我可以序列化支持表单的数据对象。

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:-1)

有没有想过使用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

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

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

有一个缺点是机器相关的解决方案。

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