- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Turn off caching on DataSource
Joined: 10-Mar-2006
I would like to turn off the caching provided by the LLBLGenProDataSource as I do not think it is necessary.
Essentially, if you are using paging and NOT EDITING your grid, you would not need the cache. Here are 2 real world situations where I believe the cache is not necessary.
1) The user 'searches' and the grid displays rows of data. In the grid, one column contains a hyperlink. They then click the hyperlink to go to the 'details' of that record. In this case, there is never a postback and the cache is never used. Also, if they 'search again', the old cached data is never used.
2) I load and entity that contains several relations. I assign those related fields to a datasource, which shows in a grid. All they can do is sort (requires refetch of course) and page (requires refetch also) through the data.
Of course I can implement both of the situations above without a datasource, but then I have to code the sorting/filtering myself.
Since I am not using the cache: I do not want it in my session - which are stored in SQL Server and require a database trip anyway I do not want in the viewstate - making the page extra large to download. I do not want in the cache - taking up memory for no reason.
Anyway to get a new cache option of 'None'?
If you don't need editing, you can just fetch the entitycollection and bind it correct to the grid, why bother with a datasourcecontrol? The whole point of the datasourcecontrol is that you can get 2-way databinding, which requires that the data is cached.
Joined: 10-Mar-2006
I disagree that is the whole point of a datasource. In fact, as you know I have been participating in a '4 page' thread about the problems with DevExpress and aspxGrid......
That whole thread is about paging inside a LLBLGenProDataSource, which is READ ONLY! Why do they want to use it - considering it is read only?
1) Sorting - you get automatic server side sorting. If I have to do what you said, then I have to write code that maps the sort requests from the grid to SortExpressions on my collections. 2) Filtering - same as #2. (Plus advantages of select parameters tied to controls)
With datasources, it is ALSO for one way databinding with a host of other features. Of course we can do this with some code, but we can also do this NOW with NO code....but it has the nasty side effect of trying to cache something, where a cache is not needed.
Convinced?
No, because if caching is disabled, two-way databinding is not possible. In the case of you trying it, it won't work and will give unexpected results. So if I add a 'no caching' option, two-way databinding shouldn't be possible. In fact, this would mean that a grid bound to it shouldn't be able to be designed as editable. That's impossible to achieve. At runtime, the entity view returned to the grid can be set to readonly.
The thing is though: you will read the manual, and know what no caching means. But in general people don't read manuals. (I also skip reading manuals in a lot occasions, run into walls, go back to the manual and ask myself why I skipped it
) So they see "Oh, I can switch off caching, cool, because I don't think I'll need it", and the grid is suddenly readonly...
I also don't see it as a big problem, because if you pick viewstate, and you don't bind a gazillion rows to the controls, why bother? It's not as if the server is burned down by the massive amount of data...
(edit) It also less optimal (costs performance) : 1 page with grid + datasource and another control with an event handler. Control raises event -> postback -> grid calls ExecuteSelect on datasource for data (it always does this!) and as the datasource didn't cache the data, it has to refetch it, which hurts performance. With caching, you don't have to.
Joined: 10-Mar-2006
No, because if caching is disabled, two-way databinding is not possible. In the case of you trying it, it won't work and will give unexpected results. So if I add a 'no caching' option, two-way databinding shouldn't be possible. In fact, this would mean that a grid bound to it shouldn't be able to be designed as editable. That's impossible to achieve. At runtime, the entity view returned to the grid can be set to readonly.
GREAT - I do NOT ALWAYS NEED two-way databinding. Correct - adding no caching makes the grid readonly and not be desinged as editable. REMEMBER, just because I am showing data in a grid (that is sortable, groupable, column reorder, etc) does NOT mean the users are editing that data!
I also don't see it as a big problem, because if you pick viewstate, and you don't bind a gazillion rows to the controls, why bother? It's not as if the server is burned down by the massive amount of data...
I cannot believe you have said this.....output all that data to the viewstate even though I know I do not need it...ugh...and dont forget if I do grouping or some other 'read only' forced deal anyway, the amount of data bound will be huge....
edit) It also less optimal (costs performance) : 1 page with grid + datasource and another control with an event handler. Control raises event -> postback -> grid calls ExecuteSelect on datasource for data (it always does this!) and as the datasource didn't cache the data, it has to refetch it, which hurts performance. With caching, you don't have to.
This is a true special situation where the caching does help.
Otis - I realize that adding this option may result in users mistakenly turning it off and having two-way databinding not work. However, that to me, is not a good reason to not have it. I want an optimized grid with an optimized experience. MOST of my grids are in fact NOT TWO WAY DATABOUND! Some are, and I will leave the caching in place. However, in the places I know what is happening and know it is readonly and not two way, I should not have to have my already bloated viewstate be bloated even more. Lots of times it is a typedview or typedlist which is readonly anyway....
Restating - I can do exactly what I am asking for with a grid. It works perfectly. however, I must write custom sorting code and filtering and fetching code....on every webform. IF I could just replace that with the features of a datasource without the caching overhead - I would be in a great place. I do not follow why this would be such an issue to have as a feature.
(To skip over the blabla to the workaround and a possible (future) solution, skip to the bottom)
WayneBrantley wrote:
No, because if caching is disabled, two-way databinding is not possible. In the case of you trying it, it won't work and will give unexpected results. So if I add a 'no caching' option, two-way databinding shouldn't be possible. In fact, this would mean that a grid bound to it shouldn't be able to be designed as editable. That's impossible to achieve. At runtime, the entity view returned to the grid can be set to readonly.
GREAT - I do NOT ALWAYS NEED two-way databinding. Correct - adding no caching makes the grid readonly and not be desinged as editable. REMEMBER, just because I am showing data in a grid (that is sortable, groupable, column reorder, etc) does NOT mean the users are editing that data!
I know, but you don't take into account how grid <-> datasource control communication works during roundtrips. For the grid it doesn't matter if the data is readonly or not: if a postback happens, e.g. due to an event handler, the data is requested AGAIN from the datasource. So it has to be there, and the only way to be able to do that is by caching the data.
Even refetching the data isn't ideal, because it could lead to a different set of data (because someone deleted a row already)
I.o.w.: what you want isn't possible unless caching is used.
The situation would be different if the grid would cache the data it got the first time, by itself. I.e.: when the data is readonly, it would simply copy the data over to strings and be done with it and not call ExecuteSelect again. However that's not how it works, Wayne
I also don't see it as a big problem, because if you pick viewstate, and you don't bind a gazillion rows to the controls, why bother? It's not as if the server is burned down by the massive amount of data...
I cannot believe you have said this.....output all that data to the viewstate even though I know I do not need it...ugh...and dont forget if I do grouping or some other 'read only' forced deal anyway, the amount of data bound will be huge....
Erm... just because you're doing grouping on the client and the data set is therefore huge, makes it our problem that the data is ... huge? Why not group on the server? Databases are optimized for grouping data, SQL is ideal for that.
Btw, fast serialization switched on makes very small datasets and it does that very fast, so it's not a big problem per se. For selfservicing users it might be a bit different, but Wayne: if you get performance problems, the first thing you should kick out is resource hogging grids. If data is readonly anyway, use a repeater on a set created by grouping data on the server.
edit) It also less optimal (costs performance) : 1 page with grid + datasource and another control with an event handler. Control raises event -> postback -> grid calls ExecuteSelect on datasource for data (it always does this!) and as the datasource didn't cache the data, it has to refetch it, which hurts performance. With caching, you don't have to.
This is a true special situation where the caching does help.
It's not a special situation, it's the majority of situations.
Otis - I realize that adding this option may result in users mistakenly turning it off and having two-way databinding not work. However, that to me, is not a good reason to not have it. I want an optimized grid with an optimized experience. MOST of my grids are in fact NOT TWO WAY DATABOUND! Some are, and I will leave the caching in place. However, in the places I know what is happening and know it is readonly and not two way, I should not have to have my already bloated viewstate be bloated even more. Lots of times it is a typedview or typedlist which is readonly anyway....
Why not bind the set directly then? Why use a datasourcecontrol ? I might sound like a broken record but building websites hasn't changed since 1993 really: write HTML and handle POST/GET requests. That's it. Today, people think it's different, but it's not. If you have to display readonly data, you could use a grid. But the grid is just a fancy way of generating a HTML table. Sure, if you want to offer the user client-side data grouping through javascript, a grid might be helpful, but then still you can just bind a set directly and be done with it.
Furthermore, IF a postback is issued, and due to the programming model of ASP.NET, the developer doesn't really run into those anymore: you bind an event handler to an event and voila, it works (but with a postback!), the data is gone if no caching is used. So the datasourcecontrol has to refetch the data, but that might be a different set.
That's unacceptable. You might find it acceptable, I don't. People expect it to work, to cache the data and if something suddenly dissapears, it gives problems for the user (developer).
So if you have performance problems, you really should do things differently, simply because all the abstraction layers on top of the HTML writer deep inside ASP.NET are all contributing to the performance needed to render your pages.
Restating - I can do exactly what I am asking for with a grid. It works perfectly. however, I must write custom sorting code and filtering and fetching code....on every webform. IF I could just replace that with the features of a datasource without the caching overhead - I would be in a great place. I do not follow why this would be such an issue to have as a feature.
It's an issue because it will cause big problems for some people. It's not something you can enable and you get MORE features, it's something you can disable and you get LESS features: not only caching doesn't occur anymore, but also postbacks make the data go away.
As I said before: IF the world would have worked in the way that the grid wouldn't request the same data from the datasource again (as it already got it) with a postback, sure, why not disable the caching. But the caching is also necessary for the data delivery after a postback. And that's something I won't disable, simply because that will give too much problems, not for developing that code but for the users using the datasourcecontrol in their pages.
(edit) I do think there's a workaround. - derive a class from LLBLGenProDataSource in your own project, doesn't matter. - add a tag to that class and use that datasource class in your form. - Override CreateStateDataObject. In that override you first call the base method. This will return an object array. At position 1, you'll find again an object array. At the position 2, you'll find the container, e.g. the collection. Set it to null. (the positions are located by enums, but these are internal, so you've to use the constants) (so the position is: base.CreateStateDataObject()[0][2]) THen return the array.
Thinking about it a bit more: my objection is centralized around the idea that a simple setting can disable more than what the developer expects. If something is added which allows the developer to disable it him/herself, it means the developer has to write some code to remove the collection for example.
At the moment it's not really possible to set the containingcollection to null after the select happened (you can, but it will give an exception).
So if I add an event to the datasourcecontrol, you could handle it, and in that event (e.g. ExecuteSelectComplete) you can for example set datasourcecontrol.EntityCollection to null. It would not affect the data being returned (as that's already retrieved) and it will make sure the collection isn't ending up in the viewstate etc. It WILL mean that with any postback, you'll run into a problem. But as you were the one who set the property to null, it's your responsibility.
Would that work?
Joined: 10-Mar-2006
know, but you don't take into account how grid <-> datasource control communication works during roundtrips. For the grid it doesn't matter if the data is readonly or not: if a postback happens, e.g. due to an event handler, the data is requested AGAIN from the datasource. So it has to be there, and the only way to be able to do that is by caching the data.
You are correct - I do not take this into account at all. Are you sure about this? For example, if I have a grid on a webpage and I click a column to sort by - that would cause a postback.....surely the grid would not re-request the data it already has and then turn around and re-request the data, this time sorted?
As I said before: IF the world would have worked in the way that the grid wouldn't request the same data from the datasource again (as it already got it) with a postback, sure, why not disable the caching.
This is EXACTLY what how it DOES WORK!! the grid already has this data in the viewstate and reconstructs it....no refetch.... Take a look here: http://www.telerik.com/DEMOS/ASPNET/Prometheus/Grid/Examples/Programming/ViewState/DefaultCS.aspx Also, using Infragistics grid before, it also does not re-request the data from the datasource on postback - it already has it. I just created an example grid using Telerik's RadGrid. During a postback, I can confirm it does NOT re-request the data...(I built an example not using your controls obviously).
If viewstate of the grid is 'on' it will NOT re-request the data on postback. So, now I have it cached in your datasource and in the grid.
From your point of view - if it IS a grid that is going to be edited - you want to have those entities available on postback - which I am guessing is why you cache (the grid will have the data it needs to reconstruct itself during postback, but will not have your 'entity objects'). However, again - if there is not 2 way binding/editing/deleting going on, I still think this is not necessary.
the first thing you should kick out is resource hogging grids. If data is readonly anyway, use a repeater on a set created by grouping data on the server.
I do not want to rebuild all the filtering, paging and sorting features of a grid on top of a repeater.
Just because the grid 'can edit/has 2 way databinding' data does not mean it has to be used for editing. Every grid has the ability to turn that off/on - yet still use all the features of a grid like sorting, filtering, paging, etc.
Why not bind the set directly then? Why use a datasourcecontrol ?
This is EXACTLY what I have been doing. However, if the user wants to filter in that grid - I have to write custom code to map the filtering into predicates and onto the data. If the user wants to sort the grid - same thing. I also have to handle the paging parameters, etc. As opposed to a datasource with ZERO code for all of that....
So if I add an event to the datasourcecontrol, you could handle it, and in that event (e.g. ExecuteSelectComplete) you can for example set datasourcecontrol.EntityCollection to null. It would not affect the data being returned (as that's already retrieved) and it will make sure the collection isn't ending up in the viewstate etc. It WILL mean that with any postback, you'll run into a problem. But as you were the one who set the property to null, it's your responsibility.
Potentially could work. However as you often say, I would like to get to the bottom of why/when you cache - as it seems unnecessary if the grid is readonly - because I have tested and the grid will not re-request the data on postback of a button on a page, etc.
WayneBrantley wrote:
know, but you don't take into account how grid <-> datasource control communication works during roundtrips. For the grid it doesn't matter if the data is readonly or not: if a postback happens, e.g. due to an event handler, the data is requested AGAIN from the datasource. So it has to be there, and the only way to be able to do that is by caching the data.
You are correct - I do not take this into account at all. Are you sure about this? For example, if I have a grid on a webpage and I click a column to sort by - that would cause a postback.....surely the grid would not re-request the data it already has and then turn around and re-request the data, this time sorted?
every button you have on your page which raises an event causes a postback and thus a refetch, or better: will run into problems as the data isn't there anymore.
It depends on the grid if it sorts on the client (no postback) or not (postback + refetch). Sorting wasn't what I was after, it's more the rest of the page which could cause a postback.
As I said before: IF the world would have worked in the way that the grid wouldn't request the same data from the datasource again (as it already got it) with a postback, sure, why not disable the caching.
This is EXACTLY what how it DOES WORK!! the grid already has this data in the viewstate and reconstructs it....no refetch.... Take a look here: http://www.telerik.com/DEMOS/ASPNET/Prometheus/Grid/Examples/Programming/ViewState/DefaultCS.aspx Also, using Infragistics grid before, it also does not re-request the data from the datasource on postback - it already has it. I just created an example grid using Telerik's RadGrid. During a postback, I can confirm it does NOT re-request the data...(I built an example not using your controls obviously).
Not all grids do that. A normal vanilla .NET grid does re-request the data. By design, all ASP.NET controls get rebound to the datasources they're bound to when the page is rendered. Almost all grids on the server call ExecuteSelect. I would be VERY surprised if the telerik grid wouldn't. (as it has to, otherwise it would reference other objects than there are present in the datasource!)
Mind you: you can't test this with LivePersistence set to false.
Trust me, I've spend 3 months writing these datasource controls. I do know when they're called and when data is necessary to be there. It might not apply to your situation, but it will apply to others. As ASP.NET is already a subject where many people struggle, I won't add code which makes it more cumbersome, even though it might fit your project.
So if I add an event to the datasourcecontrol, you could handle it, and in that event (e.g. ExecuteSelectComplete) you can for example set datasourcecontrol.EntityCollection to null. It would not affect the data being returned (as that's already retrieved) and it will make sure the collection isn't ending up in the viewstate etc. It WILL mean that with any postback, you'll run into a problem. But as you were the one who set the property to null, it's your responsibility.
Potentially could work. However as you often say, I would like to get to the bottom of why/when you cache - as it seems unnecessary if the grid is readonly - because I have tested and the grid will not re-request the data on postback of a button on a page, etc.
How have you tested that? By setting LivePersistence to false? The datasource won't refetch the data, as it has the data cached and doesn't refetch the data (as there's for example no need to do so).
Joined: 10-Mar-2006
Yes, I HAVE tested this - and that is what I am debating with you on - the results of my testing!
Trust me, I've spend 3 months writing these datasource controls
Believe me, I do trust you......but, I am getting different findings that you are!
At the end of the day, we have a core disagreement or view on how/why everything should work. You are the 'expert' in this situation - however, I am a customer in need and a customer who wants to make your product better.
So, here is a recap: You are stating in general that a grid will not work unless your llblgenprodatasource caches the data.
I _respectfully_ disagree with this. I have done testing with Telerik's RadGrid and ASP.NET's GridView and that is not true for either one of them. If you are not doing editing it is not necessary. The documentation also seems to support me on this:
From:[http://www.asp.net/Learn/Data-Access/tutorial-58-cs.aspx](http://www.asp.net/Learn/Data-Access/tutorial-58-cs.aspx) This sequence of events happens each and every time the GridView needs to bind to its underlying data. That happens when the page is first visited, when moving from one page of data to another, when sorting the GridView, or when modifying the GridView’s data through its built-in editing or deleting interfaces. If the GridView’s view state is disabled, the GridView will be rebound on each and every postback as well. The GridView can also be explicitly rebound to its data by calling its DataBind() method.
This shows that it does NOT rebind, hence reselect on every postback. Just when using the built-in editing/deleting. (Or doing obvious resorts, etc)
I put a regular grid on a webpage - attached it to an objectdatasource. That objectdatasource is hooked to the GetProducts() method that simply returns a collection. I put a button on the page that does a postback. I put a breakpoint in the GetProducts() method. It is ONLY called the first time the grid is shown. Pressing the button (causing a postback), does not cause the grid to be rebound- hence does not cause the method below to be called.
public class OrderBLL
{
public OrderBLL()
{
}
[System.ComponentModel.DataObjectMethodAttribute
(System.ComponentModel.DataObjectMethodType.Select, true)]
public OrderCollection GetProducts()
{
OrderCollection orderCollection = new OrderCollection();
orderCollection.GetMulti(null);
return orderCollection;
}
}
Otis - if I have gone wrong somewhere in my testing, please let me know. Also, every other 'datasource' offers the ability to 'disable caching', which is off by default - I do not understand why the same would not be true of yours.
The ObjectDataSource caches the data, so the second call (in the postback) to ExecuteSelect will cause the return of the cached data. (see reflector) (it checks if any of the parameters changed, if not it pulls the same set from the asp.net cache)
All .NET data source controls do this btw.
The reason is simple: the datasourcecontrol knows when to refetch the data, not the grid. It might be that the datasourcecontrol has been altered and has to refetch. The grid therefore has to call the ExecuteSelect method again.
Why else would a datasourcecontrol have to cache ANY data at all? If a bound control always cached the data anyway?
I know it sounds silly, but if I bind a grid to a datasourcecontrol and press a button I always get a call to ExecuteSelect, that's the reason the datasourcecontrol keeps the state up to date.
Especially for you, I'll spend some minutes tomorrow to re-check this for you, so this thread can be closed.
(edit) Do mind that there's a difference with Ajax grids.
(updated)
Wayne, you're right. That is: when the grid is viewed without editing. A button click indeed doesn't make it call ExecuteSelect. I should have looked first instead of relying on a year old memory what takes place when. My appologies. I of course wanted to know why I thought it would call ExecuteSelect every time, and the reason I think is that a couple of months ago we found a changed event raise issue which caused the datasourcecontrol to raise Changed events more often than required, which made a bound control call ExecuteSelect (which then didn't do anything) unnecessary
What I did was adding Debug.WriteLine calls to various places in the datasourcecontrol and also to the page. I've done 3 things: 1) Simply load the page. This is the first block of lines, till '----------' 2) Then I clicked 'Edit' on a row 3) Then I clicked a button on the page.
debug output: Block 1: page load:
LLBLGenProDataSource2 ctor on 9:52:49 LLBLGenProDataSourceView2 ctor on 9:52:49 Page_Load on 9:52:49 LLBLGenProDataSourceView2 ExecuteSelect on 9:52:49 LLBLGenProDataSourceBase SaveControlState on 9:52:49 LLBLGenProDataSourceBase SaveViewState on 9:52:49
Page Dispose on 9:52:49
Block 2: click Edit:
LLBLGenProDataSource2 ctor on 9:52:55 LLBLGenProDataSourceView2 ctor on 9:52:55 Page_Load on 9:52:55 LLBLGenProDataSourceView2 ExecuteSelect on 9:52:55 LLBLGenProDataSourceBase SaveControlState on 9:52:55 LLBLGenProDataSourceBase SaveViewState on 9:52:55
Page Dispose on 9:52:55
Block 3: click a button on the page (which sets a label)
LLBLGenProDataSource2 ctor on 9:53:01 LLBLGenProDataSourceView2 ctor on 9:53:01 Page_Load on 9:53:01 Button click handler on 9:53:01 LLBLGenProDataSourceBase SaveControlState on 9:53:01 LLBLGenProDataSourceBase SaveViewState on 9:53:01
Page Dispose on 9:53:01
It clearly shows that the edit click does a refetch, the button click doesn't. A server side sort does too cause a postback and an executeselect call.
(edit). I removed a long winded paragraphs from my part about problems an implementation of non-caching could lead to. I still think it can harm developers more than expected, but we're not here to babysit everyone.
You mentioned that other datasourcecontrols have a disable caching feature, and I didn't know that. It even turns out that ObjectDataSource for example has caching disabled by default. If MS has gone that far to disable it by default, I think it's ok for us to at least add the option (and not enable it by default ).
I'll add to v2.6 (and this is really the last thing I'll add to v2.6), a cache location option of 'None' which will cache the viewstate and other info in the viewstate but not the data.
Adding the code, gives one other problem: Sorting set to ClientSide: the 'client side' is the webserver, not the browser, so there IS a postback, but the view is sorted, not the data on the server. As there's no cached data, the grid turns up empty.
So if the collection/container is empty and ExecuteSelect is called, which is called when a sort column is clicked, and caching is none, it also has to do a fetch. This might not be expected... I'll add a note of this to the docs.
Joined: 10-Mar-2006
Great - thanks. I thought I was going crazy. I appreciate you putting up with my relintless responding, investigating this and ultimately fixing/changing this for me.
I have a neat trick for when working with a DataGrid/GridView in read-only mode. I set Viewstate to false on the actual data rows like so...
protected void GridView1_OnRowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.EnableViewState = false;
}
}
... but leave Viewstate enabled on the grid control. This rids the viewstate of the unnecessary row data but still leaves enough of the grid's state for it to work upon postback. You can even delete a row via a postback if you use the grid's 'Keys' collection to look up a row's primary key via the index of the row posted back.