Don't fire perform_work on postback (ASP.net)

Posts   
 
    
KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 31-May-2007 15:57:16   

LLBLGen v.2.0.0.0 / .NET 2 / Adapter

Hi guys,

I have an Infragistics UltraWebGrid (bound to an LLBLGen datasource) and some form fields such as textfields and drop downs on a aspx page. When submitting/saving the page it might be that there are validation errors in textfields, which can only be cought on server side. If the validation fails I just want to send the page back to the user and show an error message. I don't want to get the UnitOfWork object at this time because the user can change further things in the list. In other words, I don't want that perform_work is executed at this time.

How can I do that?? How can I decide when to get the UnitOfWork object?

Thanks in advance for your help!

jmeckley
User
Posts: 403
Joined: 05-Jul-2006
# Posted on: 31-May-2007 19:30:26   

I haven't worked with Infragistics controls. however I think it would be similar to the gridview.

with GridView you can validate in the OnUpdating or OnDeleting event. like this

protected void GridView_RowUpdating(object sender, GridViewRowUpdateEventArgs e)
{
    e.Cancel = !Page.IsValid;
}
protected void GridView_RowDeleting(object sender, GridViewRowDeleteEventArgs e)
{
    e.Cancel = !Page.IsValid;
}

or you can call page.isvalid in the DataSource control

protected void LLBLDataSource_PerformWork(object sender, LLBLDataSourceEventArgs(2) e)
{
    if(Page.IsValid)
    {
         e.Commit(e.AdapterToUse, true);
    }
}
Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 01-Jun-2007 09:46:35   

Or you may handle the PerformWork event and perform your validation first, then return from it without persisting anything if the data was invalid.

KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 01-Jun-2007 11:20:55   

Thanks for your answers! simple_smile

Your suggestions would both work to cancel the update. But what I actually want to know is how to avoid performing an update and to keep the UnitOfWork object at the same time.

Lets assume that I have a textbox, in which the user can only enter values between 1 and 3. Additionally, I have a grid with products data.

Now the user enters 4 into the textbox, adds a new product to the grid and sends the page back to the server. The validation for the textbox on server side fails. So I do not execute the grid changes in the database and send the page back to the user with an error message. Then the user corrects its input in the textbox and submits the page again. Now the page is ok and I can save all data in the database. However, the changes in the grid are gone because the UnitOfWork object will be null!! How can I get the grid changes at this time? confused

Thanks!

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 01-Jun-2007 16:22:01   

what I actually want to know is how to avoid performing an update and to keep the UnitOfWork object at the same time.

Just do nothing, don't commit the Unit of Work, so nothing will be persisted, and the UOW will remain intact. Unless you set the LLBLGenProDataSource.Refetch = true, which will re-loads the data from the database and the UOW changes will be lost.

You haven't disabled the ViewState on the Grid, have you?

KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 01-Jun-2007 19:11:27   

Unless you set the LLBLGenProDataSource.Refetch = true

I didn't explicitely set the Refetch property. So I guess it had its default value, which is true.

You haven't disabled the ViewState on the Grid, have you?

No.

I tried it again setting the Refetch property to false. To put it mildly, this leads to a very strange behaviour! disappointed This is my code:


    protected void Page_Load(object sender, EventArgs e) {
        jobPositionDataSource.Refetch = false;

        if (!Page.IsPostBack) 
            jobPositionDataSource.EntityCollection = Employee.EmployeeJobPosition;
    }

    // is called after the second postback but not before
    protected void jobPositionDataSource_PerformSelect(object sender, PerformSelectEventArgs2 e) {
            jobPositionDataSource.EntityCollection = Employee.EmployeeJobPosition;
    }

    protected void jobPositionDataSource_PerformWork(object sender, PerformWorkEventArgs2 e) {
        mUnitOfWork = e.Uow;
    }

Some explanations for my code: The grid and datasource are placed on a user control. There are several user controls (actually tabs) with a grid and datasource on it. The main page (aspx) collects all UnitOfWork objects when saving and commits it.

Now with my code the event PerformSelect is called after the second postback. What exactly is the expected behaviour? Why is PerformSelect still called? It shouldn't be called at all when Refetch is false, should it? The UOW object is still reset. It only contains the last changed rows. Additionally, after the second post back the grid list is flushed/empty!

This issue is really hard.. confused

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39914
Joined: 17-Aug-2003
# Posted on: 03-Jun-2007 14:22:21   

In general, don't touch the Refetch property, so you shouldn't set it to false or true. We had some trouble with all the page states / events and when what should be enabled (as there's not that much documentation how to write a complex datasourcecontrol) so it can be you're using an out-dated build of the runtime lib. Please be sure you use the latest build of the runtime libs.

When a postback comes and things have changed in the grid, the datasource control WILL get a call to its ExecuteUpdate/Insert methods, unless the grid simply doesn't do that because some event handler is called earlier and tells the grid not to proceed (because some value is invalid for example). As nothing has changed, the grid's call to ExecuteSelect won't or shouldn't result in a fetch. the grid then posts back again, with the changed values still in the cells, the user updates the cells again and the page posts back again. the grid then doesn't get a signal to stop so proceeds as all values are valid and calls ExecuteUpdate or ExcecuteInsert (for new rows). The datasourcecontrol will then grab the values passed in, insert them into the entities affected and create a Uow. It will then raise PerformWork.

So unless the datasourcecontrol gets a call, nothing happens. Please make sure you're running the latest runtime libs so we can rule out any event errors on our side. Also remove all calls to refetch.

Frans Bouma | Lead developer LLBLGen Pro
KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 04-Jun-2007 11:10:46   

Hi Otis

Thanks for your input. At least I understand now that I can't interfere in the communication between datasource and grid. Apparently, the ExecuteXXX methods are always fired.

I checked what version I'm running. It's 2.0.7.424. I think that's one of the latest.

As I use the infragistics grid I can't be sure if the problems don't come from that grid. So I tried the same with the standard MS grid. It doesn't work as expected as well. The example is very easy:

User control:


<llblgenpro:LLBLGenProDataSource2 ID="dataSource" 
runat="server" 
AdapterTypeName="CH.KochIT.KERPS.Data.DatabaseSpecific.DataAccessAdapter, CH.KochIT.KERPS.DataDBSpecific" 
CacheLocation="Session" 
DataContainerType="EntityCollection" 
EntityFactoryTypeName="CH.KochIT.KERPS.Data.FactoryClasses.InvoiceItemEntityFactory, CH.KochIT.KERPS.Data" 
LivePersistence="False"
 OnPerformSelect="dataSource_PerformSelect"
 OnPerformWork="dataSource_PerformWork">

</llblgenpro:LLBLGenProDataSource2>

Invoice items:

<asp:GridView ID="GridView1" runat="server" 
AutoGenerateColumns="False" DataKeyNames="Id" DataSourceID="dataSource"
  >
    <Columns>
    <asp:CommandField ShowEditButton="True"/>
        <asp:BoundField DataField="Id" HeaderText="Id" ReadOnly="True" SortExpression="Id" Visible="false"/>
        <asp:BoundField DataField="Position" HeaderText="Position" SortExpression="Position" />
    </Columns>
</asp:GridView>

And the code behind:


public partial class Modules_Invoices_DetailTabs_InvoiceItems : BaseUserControl {

    public InvoiceEntity Invoice {
        get { return (InvoiceEntity)((IParentDialogPage)Page).Entity; }
    }
    

    protected void dataSource_PerformSelect(object sender, PerformSelectEventArgs2 e) {
        dataSource.EntityCollection = Invoice.InvoiceItem;
    }

    protected void dataSource_PerformWork(object sender, PerformWorkEventArgs2 e) {
        // let this be empty for this test.
    }
}

This user control is placed on a normal aspx page.

I tried the following workflow 1. Load page --> Grid is loaded with correct entities 2. Edit an entity (click on corresponding link in grid) --> Page switches to edit mode 3. Change value and click on update (click on corresponding link in grid) 4. Grid is empty!!!!! ???

Then I tried the same workflow as described above but for the data source I changed CacheLocation="ViewState". Now the difference is that in point 4 the grid is not empty but my changes are not applied.

I also tried the same code in an empty aspx page (without using a user control) --> same result.

What's wrong with my code??? I checked the LLBLGen documentation again (Databinding with ASP.net 2.0, Adapter) but the example there uses LivePersistence = true and that also works fine on my side.

Thanks for your help.

jbb avatar
jbb
User
Posts: 267
Joined: 29-Nov-2005
# Posted on: 04-Jun-2007 16:03:31   

Hi,

first of all, I think that your performSelect function is not good. You need to fetch from the database your datasource each time because in the session mode the collection is link by reference and a datasource.clear is called when a select is throw so your entitycollection is cleared. Then try again in session mode.

KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 05-Jun-2007 09:15:26   

hi jbb,

Yes you're right! My fault! flushed Is it possible to make real copies of entity objects?

So ok, one problem is solved. But now when editing and saving an entity in the grid I can't see the new values because I load the old ones from the db in performSelect.

It would work with LivePersistence=true or if I were writing to new values directly to the db. But at this time I don't want to write it to the db.

Do you understand what I mean? How can I solve that?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 05-Jun-2007 10:57:06   

Is it possible to make real copies of entity objects?

So ok, one problem is solved. But now when editing and saving an entity in the grid I can't see the new values because I load the old ones from the db in performSelect.

It would work with LivePersistence=true or if I were writing to new values directly to the db. But at this time I don't want to write it to the db.

Do you understand what I mean? How can I solve that?

I'm not following up, sorry. I'm not sure what are you trying to do, would you please elaborate?

If you don't want to persist the changes to the database, but you want to keep it somewhere to be read again, you may use the PerformWork to save a copy of the dataSource using the CopyTo method of the entityCollection, in a session variable so you can re read it from the PerformSelect.

I'm not sure I'm even touching your issue, here.

KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 05-Jun-2007 22:00:58   

Hi Walaa

You exactly understood my question. What I wanna do is to persist the grid changes for a certain time on the web server and to write it to the webserver as soon as the user clicks on save.

... to save a copy of the dataSource using the CopyTo method of the entityCollection

Thanks! That's what I wanted to know. simple_smile

If you don't want to persist the changes to the database, but you want to keep it somewhere to be read again, you may use the PerformWork to save...

Ok I tried that. The problem is that I can only get the changes as UOW object but not the new collection. Assuming that I add 1 row in the grid, I update 1 row and I delete 1 row. How can I get the resulting entity collection??? If that is possible I think I can solve the whole thing by reading that new collection in PerformSelect.

So to sum up, I actually have just one question: How can I get the updated entity collection instead of the UOW object. It can be either in PerformWork, PageLoad or somewhere else. I tried to read DataSource.EntityCollection at different positions but it's always null.. cry

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 06-Jun-2007 10:30:50   

While you can get the entities to be deleted and the entities to be saved (inserted/updates) from the UOW object by using its member methods. (eg. GetEntityElementsToInsert()... etc).

The unit of work will hold the entities to be changes, not all the entities in the dataSource not the the original collection, since un-changed entities won't be available.

To get the complete entityCollection, I think you should use the LLBLGenProDataSource.EntityCollection property (Only valid if DataContainerType is set to EntityCollection)

I tried to read DataSource.EntityCollection at different positions but it's always null..

I tried it and it always has data simple_smile I have the EnabledViewState set to true, for both the LLBLGenProDataSource and the FormView/GridView.

KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 07-Jun-2007 08:41:33   

I tried it and it always has data I have the EnabledViewState set to true, for both the LLBLGenProDataSource and the FormView/GridView.

Ok I will try that over the weekend.. sunglasses Normally I set the cache location to session for the datasource because otherwise the data sent to the client is huge (page size is doubled in my case). But ok, I will try it with viewstate only.

In the meantime I implemented my page with a standard .NET object datasource and the standard MS grid. Still I use an LLBLGen object collection as model. This approach is described here: http://www.gridviewguy.com/ArticleDetails.aspx?articleID=139 (not exactly with LLBLGen but it can be adapted). From my point of view this is a very flexible approach and provides a lot of control over the data. It's just a bit more work though.. cry

Thanks a lot for your support. It helped me a lot to understand the connection between grid and datasource. simple_smile