views:

211

answers:

2

I have a GridView with an ObjectDataSource. I want to let the user create several objects and then save them in one go.

Background: I want to create an editor for a recipe. A recipe has base properties (like name and origin) and it has ingredients (like 100 g butter) I want the user to set all properties of the recipe and let him define its ingredients before (!!) saving it to the database. Also it must be possible to delete an ingredient from the list. Saving the recipe first and then defining the ingredients is not an option.

My Question: Where do I keep the ingredients before they are saved to the database?

This what I found out:

  1. ViewState is not an option because the GetData method of the ObectDataSource is static and therefore cannot access the viewstate.
  2. Session is not an option because users should be able to use the same page in different tabs of the same browser at the same time.
  3. Context is not an option because it does not survive the callback.
  4. Using LinqDataSource instead of ObectDataSource does not work because it does not support delete operations if the data source is not a linq data context.
  5. Using a unique ID in the QueryString (to identify the correct session object) would be a workaround but it messes up the URL.

I have been searching the web for a while and I have tried a lot of things without success.

Thank you very much for any help and any suggestions!!

A: 

Probably the best bet is to create a temp ID the first time the page loads. Store that in a hidden field so viewstate knows about it.

Use a custom class of some sort to represent the data for your grid. Instead of using a datasource control, manually bind the object using the DataSource and DataMember properties of the grid.

Store this object in cache using the temp ID you generate as the key.

On each postback, update the object in cache and rebind it to the grid.

Viewstate is the mechanism that maintains the identify on the client via the temp ID. The asp.net Cache API maintains the data state on the server.

Stephen M. Redd
Thanks for your help. I was hoping there was a more elegant way of solving this ... a hidden field with an ID to identify the session object looks a bit like another workaround to me. But I will do it this way now...Maybe .Net 4.0 will provide a better solution for this. Anybody any idea?
Tillito
I'm not sure it is a work around exactly. A "datasource" is designed to be the "source" of data, but in your case the source is a user. So you'd be using a datasource as a "data destination". The conceptually correct way to do this elegantly would be to use a client side control that maintains its own state until it is ready to commit to the server. You can do that with JQuery or related client-side components. There are also third party asp.net grids that do similar using server-side controls, but they work internally very similarly to what I described above, they just abstract it a bit.
Stephen M. Redd
A: 

As there seems to be no more elegant way to solve this, I implemented the following code into the base page class from which all my web forms inherit:

/// <summary>
/// Set an ID to identify the correct session variable (in case there are several ones).
/// Create this ID when it is needed for the first time.
/// </summary>
private string PageCallID
{
    get
    {
        if (ViewState["PageCallID"] == null) ViewState["PageCallID"] = Guid.NewGuid().ToString("N");
        return ViewState["PageCallID"].ToString();
    }
}

/// <summary>
/// Use a hashtable which is stored into the Session to save the in-memory
/// objects. This helps to keep the viewstate variable at the client small.
/// </summary>
protected Hashtable ServerViewState
{
    get
    {
        string strSessionKey = String.Format("CleverViewState_{0}", PageCallID);
        if (Session[strSessionKey] == null) Session[strSessionKey] = new Hashtable();
        return (Hashtable)Session[strSessionKey];
    }
}

With this, we can write on any web form:

ServerViewState["MyDataTable"] = myDataTable;

instead of

ViewState["MyDataTable"] = myDataTable;

However, this solution cannot be called by a static method. So I think it is more a workaround than a solution.

If anybody knows a better way to solve this, I would be thankful for any feedback!

Tillito