Strange ORMEntityOutOfSyncException (only if DataSourceCacheLocation = Session)

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

LLBLGen v.2.0.0.0 / ASP.NET 2 / Adapter

Hello,

I have a DataGrid bound to a DataSource and get an ORMEntityOutOfSyncException when I perform the following workflow. The exception only occurs if DataSourceCacheLocation is set to session!:

  1. Load page and change whatever value in the DataGrid
  2. Save list --> perform work is executed and data is written to db. The whole page is getting reloaded (see code)
  3. Execute search --> EXCEPTION! Why???


        // --> user clicked on search button
        protected virtual void btnSearch_Click(object sender, EventArgs e) {
            mDataSource.EntityCollection = LoadList();
            mDataGrid.DataBind();
            mDataGrid.DisplayLayout.Pager.CurrentPageIndex = 1;
        }

        // --> datagrid requests data
        protected virtual void dataSource_PerformSelect(object sender, PerformSelectEventArgs2 e) {

            mDataSource.EntityCollection = LoadList();
        }

        // --> datagrid writes its data to the datastore
        protected virtual void dataSource_PerformWork(object sender, PerformWorkEventArgs2 e) {
            e.Uow.Commit(mAdapter, true);
            Server.Transfer(Request.FilePath); // I reload the page in order to be 100% sure
                                                                       // that the data is reloaded. But apparently it isn't.. Why??  
        }

        private EntityCollection<OrderEntity> LoadList() {
            EntityCollection<OrderEntity> orders = new EntityCollection<OrderEntity>(new OrderEntityFactory());
            mDataAdapter.FetchEntityCollection(orders);
            return orders;
        }


I'm afraid I don't understand every detail of the communication between datagrid and datasource. From my point of view, LLBLGen should reload everything when reloading the page. But apparently, it still knows that something was update before. How is that possible? My implementation works fine if DataSourceCacheLocation is set to Viewstate! Might this be a bug? Somehow the data in the session is not properly flushed.

KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 01-Jun-2007 14:02:22   

I found the problem by myself. I didn't know that perform_work is executed several times (as much as there are changed objects).

So I implemented the Server.Transer() statement in the LoadComplete handler.

Still, some points are not clear to me:

  1. I automatically set some values in the Validator class. That's why I have to reload the whole list. Otherwise, the values I changed in the validator class would not appear in the list. Is it good design to automatically set values in the validator class? (e.g. set invoice valuta date if user set invoice on paid). I also tried it with the PropertyChanged event but this event is not fired when using a datasource.

  2. I checked the life cycle of a page that contains a datasource and a grid. When loading the page it's like that: Init --> Load --> LoadComplete -> PerformSelect -> Databound

But when saving the grid then it is like that: Init --> PerformSelect --> DataBound --> Load --> PerformWork --> LoadComplete

Why is it different when saving the page? Why isn't PerformSelect executed AFTER LoadComplete??

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

I found the problem by myself. I didn't know that perform_work is executed several times (as much as there are changed objects).

As far as I know, PerformWork is fired once for each user-initiated persisting action. (Save/Delete).

  1. I automatically set some values in the Validator class. That's why I have to reload the whole list. Otherwise, the values I changed in the validator class would not appear in the list. Is it good design to automatically set values in the validator class? (e.g. set invoice valuta date if user set invoice on paid). I also tried it with the PropertyChanged event but this event is not fired when using a datasource

Validator classes is what I'd recommend.

I have a DataGrid bound to a DataSource and get an ORMEntityOutOfSyncException when I perform the following workflow. The exception only occurs if DataSourceCacheLocation is set to session!:

  1. Load page and change whatever value in the DataGrid
  2. Save list --> perform work is executed and data is written to db. The whole page is getting reloaded (see code)
  3. Execute search --> EXCEPTION! Why???
  1. I checked the life cycle of a page that contains a datasource and a grid. When loading the page it's like that: Init --> Load --> LoadComplete -> PerformSelect -> Databound

But when saving the grid then it is like that: Init --> PerformSelect --> DataBound --> Load --> PerformWork --> LoadComplete

Why is it different when saving the page? Why isn't PerformSelect executed AFTER LoadComplete??

After saving, would you set the LLBLGenProDataSource's property Refetch = true

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

As far as I know, PerformWork is fired once for each user-initiated persisting action. (Save/Delete).

I can't confirm that. flushed In my case PerformWork is fired for every changed row. Is this controlled by the datasource or the grid? I use the one from Infragistics...

Validator classes is what I'd recommend.

Thanks! simple_smile

After saving, would you set the LLBLGenProDataSource's property Refetch = true

I tried that but it doesn't work. I guess Refetch=true is the default? Also the sequence of the fired events is still the same. PerformSelect is fired before PerformWork. That behaviour is a bit strange. Is it controlled by the datasource or grid?

Thanks a lot for reading my long support requests! I appreciate that! simple_smile

jmeckley
User
Posts: 403
Joined: 05-Jul-2006
# Posted on: 01-Jun-2007 18:01:12   

KIT wrote:

I automatically set some values in the Validator class. That's why I have to reload the hole list. Otherwise, the values I changed in the validator class would not appear in the list. Is it good design to automatically set values in the validator class? (e.g. set invoice valuta date if user set invoice on paid). I also tried it with the PropertyChanged event but this event is not fired when using a datasource.

I wouldn't recommend the validators. As this creates the situation you are currently in. Instead I would recommend either the InitClassEmpty user code region or override OnInitialized(); in either case the code would look like this

//only sets value if entity is new
if (this.Fields.State == EntityState.New)
{
   this.CreatedBy = "Me";
   this.CreatedOn = DateTime.Now;
}
//sets value if new or existing
this.UpdatedBy = "Me";
this.UpdatedOn = DateTime.Now;

when you declare a new entity (either by concrete constructors or factory classes) these fields will be set for you.

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

Hi,

With your suggestion the values are changed when loading the object. What I want to do is to set the values right before saving the entity because I want to have these new values stored in the database.

jmeckley
User
Posts: 403
Joined: 05-Jul-2006
# Posted on: 01-Jun-2007 19:20:30   

my mistake, i read your post wrong.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 03-Jun-2007 23:03:10   

Hi Kit, I'm not sure if I understand exactly your situation. Can you post your ASPX to see the configuration of LLBLGenProDataSource2 and DataGridView? simple_smile

When you save and Refetch=true, the PerformWork is executed, then PerformSelect.

Also, I'm curious about your first post, this line shouldn't work:

mDataAdapter.FetchEntityCollection(orders);

coz there is not such overload.

Please paste real code and ASXP of your LLBLGenDataSource2 and DataGridView. Also at this point, what's exactly the issue?

David Elizondo | LLBLGen Support Team
KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 04-Jun-2007 11:16:58   

hi daelmo,

thanks for your input. Yes you are right. I didn't paste original code. flushed I think for you guys it's easier to see just the important code parts rather than 1000 lines of code. I can assure that fetching entities is not the problem. I just shortened that code line a bit too much.. wink

You asked about the issue. Well, as I wrote in the second message, the problem I had in the beginning is actually solved. However, still the following point is not clear to me:

The following events are fired when saving a grid that is bound to a datasource: Init --> PerformSelect --> DataBound --> Load --> PerformWork --> LoadComplete

Why is PerformSelect called before PerformWork???

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39913
Joined: 17-Aug-2003
# Posted on: 04-Jun-2007 18:50:35   

The cycle of a page and controls on it is globally this - page loads - controls are instantiated and added to the page, e.g. grid and datasource control - state is loaded into the control instances - binding is setup between controls

at this moment, the grid will call the datasource's ExecuteSelect method. The datasource will then check if it has to select data or not. It can re-use the data of the previous select, if Refetch is false, no data has been changed and saved to the db, and no paging params have been altered (or sorter flags). If it decides the cached data isn't matching what it should return, it refetches the data and with that raises PerformSelect.

The grid gets the data, does its thing with it, e.g. render itself and then the postback ends up in the routine which made this postback happen, e.g button click or the grid posted back itself.

If the grid posted back, and it has to update data, it THEN calls ExecuteUpdate/Insert on the datasource. The datasource control then will merge the changes into the data it has in its cache and will raise PerformWork to get things done.

Frans Bouma | Lead developer LLBLGen Pro
KIT
User
Posts: 59
Joined: 04-Apr-2007
# Posted on: 05-Jun-2007 08:35:51   

Thanks! That was helpful! simple_smile