all groups > dotnet windows forms designtime > april 2006 >
You're in the

dotnet windows forms designtime

group:

BackgroundWorker with a DataAccess Layer


BackgroundWorker with a DataAccess Layer Techno_Dex
4/5/2006 4:41:11 PM
dotnet windows forms designtime:
I'm stumped with a design problem and hoping someone has an elegant
solution. I have a DataAccess Layer which contains all my database access
functionality. I would like to run all the processing requests that come
into the DataAccess Layer on a thread that is NOT the UI thread. My
DataAccess object is sitting behind a Controller class so the DataAccess
object only gets instantiated once on startup and remains throughout the
lifetime of the application. All of my forms get at the the various methods
in my DataAccess Layer by calling Controller.DataAccess.<MethodName> (i.e.
Controller.DataAccess.GetMyCustomerData(iCustomerID)). Everything I've
looked at so far for using Threads or BackgroundWorkers is throwing me into
a tailspin. If I use BackgroundWorkers, I can get the e.Result from the
BackgroundWorker_RunWorkerCompleted Event but then I can't figure out a way
to pass the results back to the calling form. I thought about creating a
custom event and delegate for each Method in my DataAccess Layer and raising
a new Event from within the BackgroundWorker_RunWorkerCompleted EventHandler
and passing the e.Result into the delegate method but that causes issues
because I could have multiple calls to the method before the first one is
finished and I'm not guaranteed that the results will get back to the right
calling class or delegate in the calling class.

Does anyone have any ideas on passing in a calling object and a delegate and
someway of keeping them all straight for each Background thread that is
called? Am I missing something or is there a better approach to handling
this issue? TIA




Re: BackgroundWorker with a DataAccess Layer msnews.microsoft.com
4/5/2006 7:36:49 PM
I might not have explained myself well enough. Here is some sample code.
My BackgroundWorker is not in the Form

//Controller.cs
public class Controller
{
private DataAccess _DataAccess;
public static DataAccess DataAccess
{
get
{
if (_DataAccess == null)
{
_DataAccess = new DataAccess();
}
return (_DataAccess);
}
}
}

//DataAccess.cs
public class DataAccess
{
private DataSet _DataSet;

public DataSet GetMyCustomerData(int ClientID)
{
//This is where the database calls occur
//This is where I was thinking about calling the BackgroundWorker
thread which also removes
//the need for the UI to know anything about how the data is
retrieved even if it's on it's own Thread
//I've thought about trying to pass in the Form1 instance and/or a
delegate on the Form1 class to this method
//also in order to call back to the Form1 class or any Form1 class
for that matter after the process has completed
}

//Tried to figure out a way to possibly to make the database calls in
here
private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{

}

//And tried to figure out a way to possibly pass back the DataSet from
the Database call in here
private void BackgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
_DataSet = (DataSet)e.Results;
}
}

//Form1.cs
public class Form1
{
private button1_Click(object sender, EventArgs e)
{
DataSet dsDataSet;
dsDataSet = Controller.DataAccess.GetMyCustomerData(12345);
}

//This was my thought as a possible delegate to get the results from the
Controller.DataAccess method call
public void GetMyCustomerDataCallback(DataSet dsDataSet)
{

}
}



[quoted text, click to view]

Re: BackgroundWorker with a DataAccess Layer Kevin Spencer
4/5/2006 7:50:54 PM
The BackgroundWorker's RunWorkerCompleted event handler is on the main
thread, so you can do whatever you need from there.

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Show me your certification without works,
and I'll show my certification
*by* my works.

[quoted text, click to view]

Re: BackgroundWorker with a DataAccess Layer Kevin Spencer
4/6/2006 7:42:39 AM
Well, your BackgroundWorker should be a member of the form. It can execute
the method in the Controller Class. The DoWork Event Handler receives an
instance of DoWorkEventArgs, which can have any object passed to it as an
argument. It also has a member called "result," to which the return value of
a function can be passed. The "result" member is then accessed in the
RunWorkerCompleted event handler, which operates in the main thread of the
Form, and can then do anything with it.

Here's an example from MSDN2:

http://msdn2.microsoft.com/en-us/library/hybbz6ke(VS.80).aspx

In your case, you would do something like the following:

public class Form1
{
private System.ComponentModel.BackgroundWorker backgroundWorker1;
private DataSet dsDataSet;

public Form1()
{
this.backgroundWorker1 = new
System.ComponentModel.BackgroundWorker();
this.backgroundWorker1.DoWork += new
System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new
System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
}

private button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = Controller.DataAccess.GetMyCustomerData(12345);
}

private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
dsDataSet = (DataSet)e.Result;
}

}

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Show me your certification without works,
and I'll show my certification
*by* my works.

[quoted text, click to view]

Re: BackgroundWorker with a DataAccess Layer Techno_Dex
4/6/2006 8:43:35 AM
I came to a similar conclusion, but am not very happy with the solution. I
would rather see the threading be handled inside of the DataAccess class in
order to hide the details and minimize the amount of code that is rewritten
in every form that uses the same DataAccess methods.... Any other
suggestions?


[quoted text, click to view]

Re: BackgroundWorker with a DataAccess Layer Kevin Spencer
4/6/2006 10:46:43 AM
The *method* is in the DataAccess class. *How* it is executed is determined
by the client using it. The client may or may not want to use a separate
thread to execute the method. However, if you wish, you can simply spawn
another Thread in the DataAccess class that performs the operation. There is
no need to use a BackgroundWorker component to do this. The class can then
raise an event when the Thread has finished executing. However, it should be
noted that a Windows Form is STA threaded, and you will still have to deal
with the threading problem in the client Form.

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Show me your certification without works,
and I'll show my certification
*by* my works.

[quoted text, click to view]
Re: BackgroundWorker with a DataAccess Layer Techno_Dex
4/6/2006 11:07:14 AM
This brings me back full circle to my original problem. Say I do spawn a
new thread in the DataAccess.GetMyCustomerData() method which queries the
database and gets the results back and raises an event. There is no way for
me (that I can think of, thus this posting) to determine which Form was the
calling form and should get the results. The use could have two instances
of Form1 open (fForm1_1 and fForm1_2). Each form is dealing with a
different Client's data (fForm1_1 -> ClientID = 1000, fForm1_2 -> ClientID =
2000). If the users executes GetMyCustomerData from both Form1 instances
back to back (say it take 5 minutes to query client data, the user starts
one process then starts the second process). Both fForm1_1 and fForm1_2
will be listening for the GetMyCustomerDataCompleted Event. They will both
get data from ClientID 1000 then both get the data for ClientID 2000.

//MDI Parent
Form1 fForm1_1 = new Form1();
Form1 fForm1_2 = new Form1();

fForm1_1.Show();
fForm1_2.Show();


//fForm1_1 instance
private button1_Click(object sender, EventArgs e)
{
Controller.DataAccess.GetCustomerDataCompleted += new
EventHandler(DataAccess_GetCustomerDataCompleted)
Controller.DataAccess.GetCustomerData(1000);
}


//fForm1_2 instance
private button1_Click(object sender, EventArgs e)
{
Controller.DataAccess.GetCustomerDataCompleted += new
EventHandler(DataAccess_GetCustomerDataCompleted)
Controller.DataAccess.GetCustomerData(2000);
}



[quoted text, click to view]
Re: BackgroundWorker with a DataAccess Layer Kevin Spencer
4/6/2006 2:06:04 PM
You have a couple of options. You can pass the data back with the EventArgs,
or you can store the data in the class and have the form fetch it when it's
ready.

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Show me your certification without works,
and I'll show my certification
*by* my works.

[quoted text, click to view]
Re: BackgroundWorker with a DataAccess Layer Techno_Dex
4/6/2006 2:11:23 PM
How does this help? There is only one instance of the DataAccess Class and
it is being used by multiple instances of 1 to N types of Forms. Each
instance Form has no way to tell if it is getting it's own data or another
instance Form's data.


[quoted text, click to view]
Re: BackgroundWorker with a DataAccess Layer Kevin Spencer
4/7/2006 9:17:42 AM
The Form has to pass the ClientID to the method, right? So, if the event
passes the ClientID back, the client knows if it is the data it is looking
for. Similarly, if the data being fetched is stored in the DataAccess class,
it can be stored in a Collection, such as a Dictionary Collection, which
enables a client to fetch the data using the ClientID.

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Show me your certification without works,
and I'll show my certification
*by* my works.

[quoted text, click to view]
Re: BackgroundWorker with a DataAccess Layer Techno_Dex
4/7/2006 12:36:11 PM
I came to a similar conclusion this morning, but thought I would return a
GUID to the calling Form on the initial call and raise an event when the
data is returned which the Form would be listening for, then it would make a
call back to the DataAccess class to get the results passing in it's GUID to
extract the results (or getting Null if the correct Form's GUID data has not
been returned yet). This would prevent any other Form from getting another
Form's data (by accident or on purpose) since it now requires a GUID Key to
get the results. I'm still not fond of either of these approaches as it
isn't very elegant (i.e. it's not a solution you would look at and say
"That's really good I should use that"). The idea behind a DataAccess Layer
is that it is pluggable/swappable so I can switch between a Local SQLDAL,
Remoting DAL, WebServiceDAL, etc... This just rubs me the wrong way. I was
thinking there was a better way and I have missed it.


[quoted text, click to view]
Re: BackgroundWorker with a DataAccess Layer Kevin Spencer
4/7/2006 4:51:16 PM
I can see your point. I wish I had more time to think about the most elegant
way to handle the issue, but I don't. :(

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Show me your certification without works,
and I'll show my certification
*by* my works.

[quoted text, click to view]
AddThis Social Bookmark Button