Friday, December 05, 2008

Oracle Application Express (APEX): Three Kinds of Session State

One of the best features of APEX is its ability to manage session state for you. One of the trickiest things you run in to when getting in to advanced development, though, is understanding just when session state is updated and when it is persisted. The easiest way I can describe this is with some examples:

1. PERSISTED Session State
Most of the time you will be dealing with persisted session state--session state that resides within the database and that is available from subsequent page requests. Any time you set an item's value with a computation or process you get PERSISTED session state. If you pass an item and value on the URL you get PERSISTED session state. If you submit a page with a text item (or radiobox, checkbox, select list, hidden item, etc.) the item will get persisted session state.

That seems like most of the ways you set item session state, but there are a couple of other ways.

2. IN MEMORY Session State (IMSS)
This category really falls in to two parts: Item Rendering and Automated Row Fetch
So . . .

2A. Item Rendering
You can set item attributes of Source and Default. Let's say we set an text item (P2_VALUE10) to have default value to C2C. Run the page and you will see an item on the page with C2C in a text box. Check the session state (use the Session link at the bottom of the page) and you will find that P2_VALUE10 does not have any session state. How is this possible? It's right there on the page with C2C, right?

The value C2C was set IN MEMORY session state. It disappears immediately when the page is done rendering; it is not saved in the database. This is not usually an issue, because you are probably going to submit the page, in which case (according to point 1 above) it will store as PERSISTED session state.

A special note on item rendering in memory session state (IRIMSS :) ): IRIMSS happens as the item is rendered. Say you have 20 items on the page, with the tenth item, P2_VALUE10, having default value of C2C. If you have any computations or conditions inside of items 1..9 that depend on P2_VALUE10, it will not have the default value. For example, say P2_VALUE3 has a display condition: Display when P2_VALUE10 = C2C. P2_VALUE3 will not show. Items 11..20, though, will see P2_VALUE10 = C2C. It can be a bit confusing.

2B. Automated Row Fetch (ARF)
Using ARF produces IN MEMORY session state as described above, with a little twist. The ARF process allows you to choose whether to put the value of the item values into IMSS right when the process is run, or as the items are rendered. In early versions of APEX it always happened as the items were rendered. In recent versions the default is to put the value into IMSS when the ARF process runs.

Why Does It Matter
Why does it matter if it is PERSISTED Session State or IMSS? I have found many cases where IMSS caused confusion and bugs. A good example is breadcrumbs. Say we have a department report, which drills in to a department form, which in turn drills in to an employee form. You could have a breadcrumb like this:

Dept Report > Dept Form > Employee

But that is not very enlightening. Wouldn't it be better to have the following?

Dept Report > Accounting > Nielsen

Which means you would define something like this

Dept Report > &P2_DNAME. > &P3_LAST_NAME.

If you used ARF to set P2_DNAME, however, but did not submit page 2, instead clicking on an employee link, P2_DNAME will be null on the employee page, resulting in the following breadcrumb:

Dept Report > > Nielsen

There are many other similar scenarios. But, the underlying cause is IMSS.

If you need persisted session state, just do your own fetch process or computation. You can leave the ARF process if you want, it won't hurt to have both.

I hope this sheds a little light on APEX session state.

11 comments:

Patrick Wolf said...

Hi Anton,

good posting! Another tricky situation with persisted session state is in case of "partial page rendering" (eg. reports) where the where-clause contains a reference to a page item. During page rendering everything is fine, but as soon as you paginate the user gets a "No data found" because the where-clause doesn't work anymore...

Patrick

Anton Nielsen said...

Patrick,

Thanks for the great example. There are many other cases but it is always hard to remember them when sitting down to blog about it.

Others should feel free to add their own examples.

Anton

Anonymous said...

Hi Anton,
Great post. I view the automated processes (ARF and ARP) as intermediate steps on the learning ladder. Using them is like using most Microsoft products because there are actions going on behind the scenes that you cannot control. Although it's more of a hassle to create your own optimistic locking, it's worth it to have more control over the page processes. When I set page items, I prefer to do it with a page process rather than within the item Source or Default fields because then all of the item setting code is in one place and often the same code is used to define more than one item.

So by using manual methods I avoid the problems, just as you suggest.

Regards,
Bill

Bill Holtzman said...

Anton,
That last comment was from me!

Anonymous said...

Hello,

Great post!
I want to ask you something:

How can you save session state through report column link?

I have a report with a column link to the same page and an item on the same page. I want when user click on the link this item to have the same value like before the click on the link.

I'm sorry for my english.

Thanks in advance !

Regards

Martin

Anton Nielsen said...

Martin,

Let's assume your report is on Page 9 and you want to link to Page 10.

Make your link a URL, not a page. Set the URL to
javascript:doSubmit('SOME_NAME_HERE');

Then have a branch on page 9, after submit (and possibly processing depending on your need). Have the branch go to Page 10 and be conditional on REQUEST = SOME_NAME_HERE.

Hope that helps.

Anton

Anonymous said...

Thx mate, great advice, it's working! :)))

Cheers

Martin

Philippe said...

Anton,

Thanks for your post. I still have a complementary question.

I have a form, filled in with values thanks to an ARF, based on an ID which I can see in the session state (the only value I see as you explained).

Now, why do I loose the value of a page item (ID) set by a link when I want to use this id to fetch in a process the values I need?

(select * into package.rowtype from table where id = :p999_id)

Unknown said...

Patrick, Anton,

Patrick mentioned in his first comment about "partial page rendering" and "No data found". I am having that exact problem. The report query is using 2 page items in the where clause, and when you attempt to go to the next or previous page, you get the "no data found". Then if you press F5 to force a page refresh, you get the data. How do I fix this issue? Still using 3.2.

Manas M said...

Hello Anton,

Can you please help me out?

I have a process (type PL/SQL) written on a page that executes On Load - After Region.
In this process I set the value of my item(hidden text box) to the value returned from my PL/SQL query.
Before the above process is executed I have one Automated Row Fetch process which executes.
Now I have a Save button on the page along with other textboxs. When i click the SAVE button I need the value from the hidden text box but when I access this value I get null.

How can I persist my hidden text box value?

Scott Wesley said...

For future readers, another example to help illustrate 2B
http://www.grassroots-oracle.com/2016/12/in-memory-session-state-use-case.html