Static ActualConnectionString problem

Posts   
 
    
alexfranke avatar
alexfranke
User
Posts: 13
Joined: 12-Apr-2005
# Posted on: 27-May-2005 18:29:33   

Hi all -- I wonder if you could help with a problem we're seeing.

Our applications go to the database through a general connection string to get configuration information, including including how and where they should connect to various other databases. This is handled by an AppInfo class, where after AppInfo theApp = new AppInfo(), theApp will contain the calling application's connection information, retrieved from the database.

AppInfo always uses a predictable connection string which is determined when its constructed. None of the connnection information ever comes from a config file.

BLL components and GUI apps set the appropriate conneciton string something like this:

AppInfo a = new AppInfo();
DbUtils.ActualConnectionString = a.ConnectionStringDev;
// continue with DAL access

Because ActualConnectionString is static and other apps might use the same DAL as it uses, AppInfo only changes the ActualConnectionString temporarily and only for as long as it needs to use it. Something like:

string temp = DbUtils.ActualConnectionString;
DbUtils.ActualConnectionString = _AppInfoConnectionString;
// Do DAL access stuff...
DbUtils.ActualConnectionString = temp;

Problem is that we often get an exception that says the connection string is not defined in the config file, even though we're explicitly setting it and resetting it in code. I expect this could happen if some static constructor checks the config file, but then we'd need to set the connection string every time a DAL object is referenced regardless of whether or not we're going to the DB... That doesn't seem to make sense.

Any ideas on how we might get this working? Should we be using a different DAL DLL for AppInfo? (But I'd prefer to have one DAL for each database.) Without using the adapter model (too far down self-servicing path), is there a way to use non-static connection information? (We expect that temporarily changing static class members could cause problems if we launch new threads, so we don't do that in AppInfo.)

Thanks so much, Alex

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 28-May-2005 12:28:51   

Hmm.

When the first connection has to be made in the generated code, the connection creation routine in DbUtils (CreateConnection) checks if ActualConnectionString is empty. If so, it reads it from the config file and sets ActualConnectionString. Otherwise it uses ActualConnectionString's value.

I'm not sure if you call your connectionstring construction code in a static constructor. If not, could you try that please? That way, you're sure the code is ran before the first connection is made.

Frans Bouma | Lead developer LLBLGen Pro
alexfranke avatar
alexfranke
User
Posts: 13
Joined: 12-Apr-2005
# Posted on: 31-May-2005 16:44:16   

Hi Otis -- thanks for the quick reply.

We tried putting the code that sets the connection in the static constructor, but that led to some problems with the components stepping on eachothers toes, so to speak. DBUtils gets the connection string of the most recently referenced class.

// Problem if we set connection strings in static constructors
AppInfo app = new AppInfo(); // DBUtils now has connection string #1 (req'd by AppInfo)
MyBll.SomeStaticMethod();  // DBUtils now has connection string #2 (req'd by MyBll)
app.Refresh(); // EXCEPTION AppInfo class tries to use conneciton string #2 to access DB.

So we added the conneciton setting code to the constructors so that whenever an instance of an object is created, it can set the connection string for its purposes. And because the AppInfo class is most often called by other classes, we set it up to clean up after itself by resetting the connection string after it uses it to what it was originally.

string temp = DbUtils.ActualConnectionString;
DbUtils.ActualConnectionString = _AppInfoConnectionString;
// Do DAL access stuff...
DbUtils.ActualConnectionString = temp;

This allows something like this:

AppInfo app = new AppInfo(); // DBUtils now has connection string #1 (req'd by AppInfo)
MyBll bll = new MyBll();  // DBUtils now has connection string #2 (req'd by MyBll)
app.Refresh(); // AppInfo sets string to #1 temporarily, then resets it to original string 
MyBll.SomeMethod();  // Uses connection string #2 because AppInfo has reset it.

We get the config file error even when DAL objects are referenced, even if we're not going to the database. So we've been putting the above set/reset code around all references to DAL objects to get around it.

// Throws an exception if connection string is empty
foreach ( MyTableEntity e in MyTableEntityCollection ) {
   // Do something...
}

So we need to do this:

string temp = DbUtils.ActualConnectionString;
DbUtils.ActualConnectionString = _AppInfoConnectionString;

foreach ( MyTableEntity e in MyTableEntityCollection ) {
   // Do something...
}

DbUtils.ActualConnectionString = temp;

It looks like what we might need to do is disable the code in DBUtils.CreateConnection() that checks to see if ActualConnectionString is empty (because we'll never be going to a config file for this info). I don't know what affect this would have on the rest of the code... Thoughts?

jtgooding
User
Posts: 126
Joined: 26-Apr-2004
# Posted on: 31-May-2005 17:10:33   

Hmm I didn't even know about that property /sigh.

I created a static class called SHIPDBConnection or something similiar, it builds a connection string for us after setting a couple of properties, then we pass SHIPDBConnection.GetConnectionString on each of our Adapter declarations to overcome the lameness of Config files, I really wish MS would of never thought of those damn things, simply because they don't work everywhere.

John

alexfranke avatar
alexfranke
User
Posts: 13
Joined: 12-Apr-2005
# Posted on: 31-May-2005 19:54:13   

Looks like you're using the adapter scenario. We're pretty far down the path of the self-servicing scenario.

Our AppInfo class essentailly does what config files are supposed to do, but gets all the configuration settings from the database with a predictable connection string. It looks la lot like your static class.

Thanks for the input, Alex

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 01-Jun-2005 10:21:31   

Though what you're trying to do is to use a connection string on a per-call basis, which is not supported for selfservicing, as it uses a single connection string for the whole appdomain. Or I 've misinterpeted your problem.

Frans Bouma | Lead developer LLBLGen Pro
alexfranke avatar
alexfranke
User
Posts: 13
Joined: 12-Apr-2005
# Posted on: 01-Jun-2005 18:37:03   

Basically, that's what we're trying to do.

We're basically trying to work around the single static connection string of the self-servicing model by setting/resetting the static connection string only as long as the object needs it. This seems to be working so far, so long as we set/reset the static connection string before and after each reference to LLBLGen-generated classes, too.

In hindsight we probably should have gone down the adapter path; alas, we didn't.

Would a better work-around be to build a second LLBLGen project that uses the adapter model only for the class that uses the different connection string (AppInfo)? If so will both self-servicing- and adapter-model LLBLGen components coexist peacefully in the same project?

Or are we doomed to rewrite everything using the adapter model?

Thoughts?

Thanks again for all your assistance and input!

-Alex

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 01-Jun-2005 23:23:43   

alexfranke wrote:

Basically, that's what we're trying to do.

We're basically trying to work around the single static connection string of the self-servicing model by setting/resetting the static connection string only as long as the object needs it. This seems to be working so far, so long as we set/reset the static connection string before and after each reference to LLBLGen-generated classes, too.

In hindsight we probably should have gone down the adapter path; alas, we didn't.

Would a better work-around be to build a second LLBLGen project that uses the adapter model only for the class that uses the different connection string (AppInfo)? If so will both self-servicing- and adapter-model LLBLGen components coexist peacefully in the same project?

If you use this multi-connection string for a small part of your application, you can indeed create an adapter project as well for that. Be aware of the fact that an adapter entity can't be used with a selfservicing entity, the layers are separated. if thats not what you want, you have to chose either one.

Your requirement is not solveable with selfservicing, you will run into problems.

Or are we doomed to rewrite everything using the adapter model? Thoughts? Thanks again for all your assistance and input!

Porting to adapter is some work, though its often easier than anticipated. What's a bit of a problem when porting selfservicing to adapter, is the usage of lazy loading which isn't present in adapter, and which thus requires extra code.

Frans Bouma | Lead developer LLBLGen Pro
alexfranke avatar
alexfranke
User
Posts: 13
Joined: 12-Apr-2005
# Posted on: 02-Jun-2005 16:53:02   

...you can indeed create an adapter project as well for that. Be aware of the fact that an adapter entity can't be used with a selfservicing entity, the layers are separated.

Okay -- I don't think this will be a problem.

Your requirement is not solveable with selfservicing, you will run into problems.

Our work-around seems to be working -- do you have a problem in mind that we might run into? To be safer we can lock DBUtils while the code that changes the connection string runs. Somehting like: (I believe this would have the effect we want -- requiring other threads to wait until this is finished before it can access the connection string.)

lock (DBUtil) {
string temp = DbUtils.ActualConnectionString;
DbUtils.ActualConnectionString = _AppInfoConnectionString;
// Do DAL access stuff...
DbUtils.ActualConnectionString = temp;
}

...is the usage of lazy loading which isn't present in adapter...

We're going to look into the adapter model -- We tend to use the prefetch paths to avoid lazy loading so I'm hoping the change might not be too bad.

Thanks again for your assistance and input! -Alex Franke

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39933
Joined: 17-Aug-2003
# Posted on: 03-Jun-2005 09:48:07   

alexfranke wrote:

Your requirement is not solveable with selfservicing, you will run into problems.

Our work-around seems to be working -- do you have a problem in mind that we might run into? To be safer we can lock DBUtils while the code that changes the connection string runs. Somehting like: (I believe this would have the effect we want -- requiring other threads to wait until this is finished before it can access the connection string.)

lock (DBUtil) {
string temp = DbUtils.ActualConnectionString;
DbUtils.ActualConnectionString = _AppInfoConnectionString;
// Do DAL access stuff...
DbUtils.ActualConnectionString = temp;
}

That's indeed a solution, though it can hurt performance a bit of course. If you don't lock, the chance is you will run into errors due to a wrong connection string, that's what I was referring to simple_smile

Frans Bouma | Lead developer LLBLGen Pro