Global datasets

G

Guest

Hi,

using c#, 1.1

I know that we are not supposed to use global variables etc. in c#

I am having a problem, but not sure how to resolve. I did have another post
here, but may have over confused things, so I will start afresh.

An example of what I want to do...

namespace MyDataSet
{
public class MyDSClass
{
public DataSet MyDS
{
// Do the dataset stuff.
return MyData;
}
}
}


I want to be able to instantiate the above code only once per page load and
return a dataset.

in my page...

using MyDataSet;
namespace MyPage
{
public class MyPageClass : System.Web.UI.Page
{
private void Page_Load(object sender, eventargs e)
{
// I need to open the dataset created in the MyDSClass, without
re-instantiating it. If it needs to re-instantiate, then only do it once.

MyDataGrid.DataSource = MyDS;
MyDataGrid.DataBind();
}
}
}

So, the above code wants to use the dataset, but not have to create it. If
it has to be created, then I need to do it, but then other controls that use
it should not have to re-create it once it has re-created.

using MyDataSet;
namespace MyUC
{
public class MyPageClass : System.Web.UI.UserControl
{
private void Page_Load(object sender, eventargs e)
{
// I need to open the dataset created in the MyDSClass, without
re-instantiating it. If it needs to re-instantiate, then only do it once.

MyUCDataGrid.DataSource = MyDS;
MyUCDataGrid.DataBind();
}
}
}


What I am trying to avoid is to have to go to the database each time MyDS is
needed. When the page is run, I only want to have to go to the database once,
to build my dataset. I want to be able to use that dataset in the page, or
control that the page hosts.

How can I make my dataset "global" and how do I then view the "global"
dataset in each control without creating a new dataset each time it is
required?

All help is appreciated. Please do ask me questions if needed so that I can
get this resolved.

Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
D

Dan Bass

David,

From what I can tell, you're confusing "Global" with "Cached" or "Session"
objects... Are you trying to building a dataset object once, then have
subsequent page refreshes use the cached object?

I punched "ASP.Net session objects" into google and got this link straight
away which goes into the details a bit more...
http://www.aspfree.com/c/a/ASP.NET/Application-and-Session-Objects-in-ASP.NET/

If this is not what you want to do, or you want more help on it, let me
know.
Thanks.
Dan.
 
G

Guest

Hi,

No, I am not thinking of cache or session. That is not what I want.

I want to create a dataset at the start of the page process. During the
page, I want to use that dataset in many places. The dataset I refer to is
actually a menu system built from the database.

examples of use...

1. Creating a breadcrumb trail.
2. Building the main navigation.
3. Building the sub navigation.
4. Knowing where I am so that objects on the page resond accordingly.

What I don't want (in the above scenario) is to create the dataset 4 times.
I want to use it in 4 places. This can be in the page itself, in can be in
the breadcrumb usercontrol, it can be in the main navigation user control.

There is no point in contacting the database 4 times for exactly the same
data. This is expensive and time consuming. So, I want to create it only once
at "global level" for the page and various page objects use it.

I don't need to cache it (yet anyway). At the moment, I am happy to create
it for every call to the page, but only once in the life of the call to the
page.

How do I do that?


Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
D

Dan Bass

David,

Then I assume that what you mean by global is that during the page loading
sequence, you have different objects that all need the same dataset?

If this is the case, then either create the dataset, and pass it into what
ever objects require it (either setting up a property on that class, or
passing it in as a method parameter), or, create a static instance
(something like a singleton object I suppose) so that each time you need to
reference the dataset, you're getting the same "global" instance.

The first method of doing things is far better... Since everything you've
described is intrinsic to having a datasource, then it makes sense to have a
DataSet property on each class, so that you, as I've said, first create the
dataset you need, calling the database and retrieving the data, then
creating each object and assigning this instance of your dataset to the
property so that each object then can use it in turn...

Doesthis make more sense? If not, keeping asking away!
Thanks.
Dan.
 
B

bruce barker \(sqlwork.com\)

just add a member variable:

using MyDataSet;
namespace MyPage
{
public class MyPageClass : System.Web.UI.Page
{
private MyDataSet MyDS = null;


private void Page_Load(object sender, eventargs e)
{
MyDS = InitDataSet(); // routine to query and return dataset.

MyDataGrid.DataSource = MyDS;
MyDataGrid.DataBind();
}
}
}
 
G

Guest

Hi Bruce,

If I did this, and each of my controls as well did this, then won't the
InitDataSet() be called for every control that uses it, hence re-creating the
dataset each time?

I don't want to be creating a dataset (in the initdataset) for every time I
want to use it...

Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
G

Guest

Hi Dan,

Thanks for sticking with me on this... your assumption is correct. I just
want to create the dataset once (as it is a database process, hence process
expensive) and be able to use it any time I choose, wether in a page or
control.

For the first method, doesn't that assume that the original dataset class
needs to know what classes will want to use it? The way I am visualising this
is that the dataset pushes its data into the page or user controls... I need
to have the dataset not know what wants to use it, just that it is there for
anything/anybody to use.

I have never (knowingly) written a singleton, so I don't know anything about
these. Can you give me a quick example of how I would write one and how I
would call it from within my pages/controls?

Thank you for the help so far...

Regards,
Dave Colliver.
http://www.MatlockFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
D

Dan Bass

Sticking with the first method again. The answer is no. The dataset class
doesn't care who references it. All it knows is that it contains the data in
its own object instance. It's up to the (typically) Page_Load event method
to then decide what controls exist that need this instance, and then assign
the data set to it.


The algorithm for Page_Load would look something like this:

Create my DataSet
Populate my DataSet from the Database

Create my CrumbTrail Object
Assign the Dataset to the CumbTrail Object (something like
CrumbTrailObj.DataSetProperty)
Do some CrumbTrail "stuff"

Create another control object instance
assign the dataset to this object
Do some processing on this object

etc...
 
G

Guest

So, if I need to use it in a user control as well as a page, the user control
also has a page_load. If I stick the code in the user control the same way,
as well as the page, then the code runs twice (doesn't it?)

What I don't want to do is to have all my controls reference the page. It
has to reference the dataset class (or whatever it is I need to reference...)

Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
G

Guest

Right, I understand that, but that means that all my pages control the
controls, so the page pushes onto the control.

While this is a possibility, the pages will be templates and may never know
what controls are added. For slightly more complexity, my page codebehind is
not derived directly from system.web.ui.page, but from my own page class
which does derive from system.web.ui.page. I need to handle this in my page
class.

I need to have a degree of seperation. I need the dataset to be at a lower
level that anything above it, be it my derived page, the page codebehind,
user control or whatever can just see it. It really should be pull rather
than push.

Thanks for (still) sticking with me... It might be a tough one to crack.

Are you familiar with Microsoft CMS? If so, think how the .Channels system
works... I can't imagine that each time a CMS or control wants to know where
it is in the channel hierarchy, it goes and generates the channel structure
each time.

Regards,
Dave Colliver.
http://www.DerbyFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
D

Dan Bass

David,

At this point it's probably worth taking a step back and describing a bit
more what you are trying to do. For a minute, forget Page_Loads, Global
variables and user controls, and try to describe, independently of ASP.Net
or any other techonology, what you are doing.

Again, what I'd do is to have a property on the usercontrol that is a
DataSet object, then when the page creates/loads the control it passes an
instance of the DataSet through to that control. Now I know you've said that
your pages may never know what controls are added, but this is, well,
impossible. Some code somewhere add's the controls to the page. So whether
it's done at design-time, or dynamically at run time, something is adding
the controls to the page. It is as this point that the DataSet is created,
and passed into the controls.

If you're still not in agreeance with this approach ( ;-) ), then go ahead
on the first part, and descibe broadly and generally what it is you're
trying to accomplish and we'll see where we go from there.

Thanks.
Dan.
 
G

Guest

Thank you for sticking with me.

I may be mis-interpreting what you are advising me. If I am, I apologise.

I need a dataset (actually, an ienumerable, based on the datatable, but
saying dataset would make things simpler and I can take it from there) that
is the menu structure of my site.

When the dataset is created is of no matter, but all objects (pages,
controls, UCs etc) must be able to read it (pull from the dataset). The
dataset must only be created once, but can be read by no, or many items that
require to read it.

The dataset class itself should not know about the objects that call it. It
has to be the object that pulls the data. To me, this is then a global
dataset, a dataset that can be seen by all objects.

Imagine a classic asp scenario...

'Create dataset. PSEUDO CODE, NOT ACTUAL
DS = createobject("recordset")
'This DS could be in a seperate include file is need be...


function CreateMenu
'Use DS here
end

function CreateBreadCrumb
'Use DS to write breadcrumb
end

function BuildPageContent
'No need to use the DS here
'but should I need to, it is available.
end


As an aside, I tried creating a singleton last night (after doing some
looking), but that is not quite working properly. Probably because I don't
really understand (yet) what I am doing with a singleton.

Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
D

Dan Bass

David,

The singleton architecture was simply a way of having a "create once, use
many" type scenario...

What you've said suddenly shed light on the situation, if you're coming from
an ASP background into this, then I can understand why you're trying to go
about what are. Unfortunately for you though, I'd still have to come back to
what I said before! ;-)

Typically I'd see it like this:

-------------------------- Page Psuedo Code
class myPage
{
DataSet myData = null;

void Page_Load (...)
{
if ( !Page.IsPostback )
{
if (myData == null)
{
// create and populate dataset here
}

// pass the data set we've created through to the controls on
the page
// If the controls are loaded dynamically, then where ever the
controls
// are loaded should contain this logic...
foreach (Control on the page)
{
eachControl.MyDataSet = myData;
}
}
} // end of Page_Load

// other page code
}


-------------------------- User Control Code
class myUserControl
{

// define this dataset locally and ensure it can be referenced as a
property
DataSet myData = null;
public DataSet MyDataSet
{
get { return myData; }
set { myData = value; }
}

void Page_Load(...)
{
if ( myData != null )
{
// bind the DS to the control here... Note we should already
have
// a valid instance here since the Page gave us a valid DS
before this
// method is executed.
}
} // end of Page_Load

// other control code
}


Hope that helps, and if not, keep probing, we'll get there. ;-)

Dan.
 
G

Guest

Hi,

Thank you so far...

I understand what you are saying here and I have done similar in the past
(and done it the other way around, where the UC calls the property from the
page instead of the page pushing the property).

Do you know Microsoft CMS? Here is what I am trying to achieve with slight
differences.


Channels MyChannels = CmsHttpContext.Current.Channel.Channels;

foeach (Channel ch in MyChannels)
{
Response.Write ch.DisplayName;
}

Now, what I notice is that the MyChannels is not using a "New" statement. So
(I may be assuming wrong) what I assume is that the
CmsHttpContext.Current.Channel.Channels is already instantiated and running.

I can quite simply use the lines above ANYWHERE in my code and it will work.
No mucking about with properties, pushing datasets or anything like that.
(obviously, there is a using clause as well).

To add to the confusion, I need to develop this at a slightly lower level.

My page codebehind class is...

class page : MyOwnPageClass.Page

My own page class is...

class Page : System.Web.UI.Page

I use a similar sort of thing for my controls. This will allow any developer
to create pages deriving from my page class with the functionality that I
need to add to the page.

Coming back to singleton, I only want to create it once and use many, but I
am not sure of the scope of the singleton. At this point in time, I want the
page to create the menu (somehow) and be available for the life of that page.
(doesn't have to survive refreshes, postbacks or anything, just the instant
the page is running.)


Regards,
Dave Colliver.
http://www.Burton-on-TrentFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
G

Guest

The singleton looks like it has scope across the application.

I have been modifying my project, build, run and the menu shows (not yet the
way I want), but if I refresh, the menu disappears. This could be due to a
property in the singleton...

public static SiteFolders Folders
{
get
{
if (mObj == null) // only ine instance is created
mObj = new SiteFolders();

return mObj;
}
}

but it looks like mObj has something, but nothing is returned...

Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
D

Dan Bass

David,

I'm afraid I've not looked into the MS CMS so can't relate to what you're
saying...

In your below example though, Channels needs to have been created somewhere,
as you said. The reason you can use the code anywhere is because
CmsHttpContext obviously has global scope. It'll be global because it's
inherent to the context it is in, created at an earlier point, then exposed
as a property. From this I'm understand your query a little more, I suspect
there is some parent class here that is initialising these objects "under
the hood".

Basically, to get to the same point with the dataset, you WOULD follow the
property route. Because you can't see that how the channel array is
populated, it doesn't mean that you got the "global-ness" (there's a new
one!) of the object for free... the framework outside what you saw did this
work to give you access to this object.

Good Luck!
Dan.
 
G

Guest

I think I may have something, based on a singleton (I think).

public class Folders
{
private static Folders mObj;

public Folders()
{
Response.Write("something");
}

public static Folders SiteFolders
{
get
{
if (mObj == null)
mObj = new Folders();

return mObj;
}
}

private int _FolderID;

public int FolderID
{
get { return _FolderID; }
set { _FolderID = value; }
}

}


In my page, I can do something like...

MyNS.Folders MyFolders = MyNS.Folders.SiteFolders;
MyFolders.FolderID = 20;
Response.Write(MyFolders.FolderID);

With my response.write in the constructor of the Folders class, I can see
that no matter how many times I call the class using the code above, the
constructor is only called once.

HOWEVER, I have also found that each time I refresh the page, the
constructor is never called again, unless I re-build the project. It seems
that the object persists in memory. Whilst this may not be a bad thing, I do
need some way to kill this persistence, for example, if I add new folders.
How can I do that?

Also, can you see anything wrong with my code? I will continue with what I
have and see how far I can take it.

Thanks for your help.

Regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 
D

Dan Bass

First thing I notice is your constructor for Folders should be private.
Otherwise you can delcare it outside of the singleton pattern and it breaks
the concept. By being private only SiteFolders can create a new instance.

The second thing you've encountered is the use of statics in ASP.Net... In a
windows form application, the use of static keeps the object in memory until
the application is closed. So if you have a static integer that acts as a
counter in an object, the object can be destroyed, and recreated, and the
value in that static will persist if it's not explicitly reset. But on the
web side of things, static's are used to store Application wide data. So if
one user came in and the object was created, then a second user browsed the
page, they'd be referencing the same data as the first.

Now you'll never guess what, but I've gone back to the starting point I made
in the first thread. You're looking more into cached objects, rather than
global, in that the object may be hidden away somewhere for set period
(whether the life of the page or life of the session) rather than a global
object that's about for the lifetime of the application. I've never been too
sure of the scope and duration of objects that are made static, and have
tended to move towards session objects that are persisted on a per user
basis...

So we've got 3 things to look at.
- Application wide data store... It's initialised typically in the
Application_Start event method and each user hooks into the same data
- Session wide data store... Each user has their own object, but it's
typically initialised at the start of the session when the user connects for
the first time, and expires with their session.
- Local data store... This comes back to having an object on the Page
object, that is then passed into each object that uses it (sounding like a
broken record player I suspect). This time the object is created typically
each time on a post back, and is expired once the postback cycle is
complete. So the life of the object is really a few seconds while the page
loads up the data.

How long do you need to keep your data for? If it's just for the cycle of a
page loading up, then 3's the answer I'm afraid.

Cheers
Dan.
 
G

Guest

Thank you Dan, your answer is helping me a lot.

A lot of my learning is by example. Since I started this particular project,
I have learned so much, such as inheritance, overrides, bubble events and now
singleton and static. I still have a long way to go, but I suspect I will
still need to learn much more before I reach my goal. (This is a large
project and has a huge scope, which will hopefully take me from an
intermediate level C# programmer to an advanced level C# programmer).

With what I have learned just in this thread alone, I can apply to other
areas of the project, Folders will only need to be at page level (at this
point in time), but other areas will need to be at session and others at
application.

If I remove static, then that will make the life of my mObj expire on the
page level? That could get me round another problem. I have noticed that when
I refresh the page, I lose information after I have enumerated (I have
modified this code to IEnumerate), but have found that .Reset() will bring it
back again... I was looking at ways to run the reset within the class, but
couldn't make it work, but if removing static makes it work, then I am happy
again. (I don't want to have to force future programmers to call reset
everytime.)

I did have Folders as private, but I had problems making it work. I will try
again now that I have got further with it.

The way I thought of caching is the generally known way, such as page
caching, sticking items in session or application variables or into the
viewstate. None of these really appealed to me for the purpose of this.
Apologies if this has caused a wasted journey to the solution.

So, one more question, with what I have here in this code, if I make the
"Folders" static, and I make a change to the database, I need to somehow
update the static folders. How can I trigger the update?

Thanks and best regards,
Dave Colliver.
http://www.NottinghamFOCUS.com
~~
http://www.FOCUSPortals.com - Portal franchises available
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top