O
Oyvind
I'm working on a Windows forms/C# database application. My background is
6-7 years of VB 4 - 6, MS Access, VC++, mixed in with a lot of T-SQL and MS
SQL Server in general and some OOA/OOD.
Previously, I haven't been overly impressed with the capabilities of the
various "graphical" data access tools that have been provided with VB etc.
Though deceptively simple to get started with, IMHO they haven't provided
the necessary flexibility when the going gets tough and (especially) the
business rules start piling up.
So, when starting on my project I discarded data sets and all that
complexity in favor of using the simple data reader to retrieve my data.
All updates, inserts and deletes are handled through stored procedures, and
the select statements are dynamically created in the appropriate data access
classes. It's a conceptual n-tier architecture, where the GUI only
interacts with business classes, and see no underlying data reader or
similar objects. The architecture of my business layer is, briefly, as
follows:
[Serializable]
public class Contact
{
int m_contactID;
string m_name;
// etc...
public Contact()
{}
public int ContactID
{
get
{
return m_contactID
}
}
public string Name
{
get
{
return m_name;
}
set
{
m_name = value;
}
}
// more property get/set statements
public void Get(int contactID)
{
IDataReader dReader = ContactDBAccess.Get(contactID); // calls a
static method
if(dReader.Read())
Populate(dReader);
dReader.Close();
}
public void Save()
{
IDataReader dReader = ContactDBAccess.Save(this);
if(dReader.Read())
Populate(dReader);
dReader.Close();
}
public void Delete()
{
ContactDBAccess.Delete(this);
}
internal void Populate(IDataReader dReader)
{
m_contactID = Convert.ToInt32(dReader["ContactID"]);
m_name = Convert.ToString(dReader["Name"]);
// etc...
}
}
// An example of a collection class. My actuall collection
// classes inherit from a more complex custom collection class
// and are more strongly typed
[Serializable]
public class ContactCollection : ArrayList
{
public ContactCollection()
{}
public void Get()
{
// E.g. a metod to retrieve all contacts in the DB
IDataReader dReader = ContactDBAccess.Get();
Populate(dReader);
dReader.Close():
}
private void Populate(IDataReader dReader)
{
Contact newContact;
while(dReader.Read())
{
newContact = new Contact();
newContact.Populate(dReader);
base.Add(newContact);
}
}
}
internal class ContactDBAccess
{
static internal IDataReader Get(int contactID)
{
string sql = SQLSelect + " and ContactID = ?";
OleDbParameter para = new OleDbParameter("@ContactID", contactID);
DBConnection db = new DBConnection(); // a custom class to
provide basic db access functionality
// Call a custom function that takes a string and a parameter,
// and returns an OleDbDataReader or similar. An
// overloaded version will, e.g., take an array of OleDbParameters
OleDbDataReader myReader = db.ExecRead(sql, para);
return myReader;
}
static internal IDataReader Get()
{
// E.g., returns all records
}
static internal IDataReader Save(Contact saveObject)
{
// Code to save the passed object to the db and return the new
// ContactID if this is a new contact
return Get(contactID); // look up the added/updated contact and
return it to the caller.
}
static internal void Delete(Contact deleteObject)
{
// code to delete the contact
}
static private string SQLSelect
{
get
{
string sql = "SELECT ContactID,
+ "Name "
+ "FROM Contact WHERE 1=1 ";
return sql;
}
}
}
The GUI only sees and accesses the Contact and ContactCollection classes.
This has given me a pretty flexible business layer, but as you can see
there's a fair amount of boiler plate code in there. Now, I realise that I
may have pretty much replicated the functionality of data sets. My question
is really whether or not I may have just generated a ot of extra work, and
would have been just as well off with just using data sets. Would they
offer any real advantages without sacrificing too much of the control I
meant to achieve by using the strategy outlined above? I'm fully aware of
the capabilities of the data sets to consume data from XML etc, but then I
could always code that capability into my existing classes, too.
TIA,
OyvindS
6-7 years of VB 4 - 6, MS Access, VC++, mixed in with a lot of T-SQL and MS
SQL Server in general and some OOA/OOD.
Previously, I haven't been overly impressed with the capabilities of the
various "graphical" data access tools that have been provided with VB etc.
Though deceptively simple to get started with, IMHO they haven't provided
the necessary flexibility when the going gets tough and (especially) the
business rules start piling up.
So, when starting on my project I discarded data sets and all that
complexity in favor of using the simple data reader to retrieve my data.
All updates, inserts and deletes are handled through stored procedures, and
the select statements are dynamically created in the appropriate data access
classes. It's a conceptual n-tier architecture, where the GUI only
interacts with business classes, and see no underlying data reader or
similar objects. The architecture of my business layer is, briefly, as
follows:
[Serializable]
public class Contact
{
int m_contactID;
string m_name;
// etc...
public Contact()
{}
public int ContactID
{
get
{
return m_contactID
}
}
public string Name
{
get
{
return m_name;
}
set
{
m_name = value;
}
}
// more property get/set statements
public void Get(int contactID)
{
IDataReader dReader = ContactDBAccess.Get(contactID); // calls a
static method
if(dReader.Read())
Populate(dReader);
dReader.Close();
}
public void Save()
{
IDataReader dReader = ContactDBAccess.Save(this);
if(dReader.Read())
Populate(dReader);
dReader.Close();
}
public void Delete()
{
ContactDBAccess.Delete(this);
}
internal void Populate(IDataReader dReader)
{
m_contactID = Convert.ToInt32(dReader["ContactID"]);
m_name = Convert.ToString(dReader["Name"]);
// etc...
}
}
// An example of a collection class. My actuall collection
// classes inherit from a more complex custom collection class
// and are more strongly typed
[Serializable]
public class ContactCollection : ArrayList
{
public ContactCollection()
{}
public void Get()
{
// E.g. a metod to retrieve all contacts in the DB
IDataReader dReader = ContactDBAccess.Get();
Populate(dReader);
dReader.Close():
}
private void Populate(IDataReader dReader)
{
Contact newContact;
while(dReader.Read())
{
newContact = new Contact();
newContact.Populate(dReader);
base.Add(newContact);
}
}
}
internal class ContactDBAccess
{
static internal IDataReader Get(int contactID)
{
string sql = SQLSelect + " and ContactID = ?";
OleDbParameter para = new OleDbParameter("@ContactID", contactID);
DBConnection db = new DBConnection(); // a custom class to
provide basic db access functionality
// Call a custom function that takes a string and a parameter,
// and returns an OleDbDataReader or similar. An
// overloaded version will, e.g., take an array of OleDbParameters
OleDbDataReader myReader = db.ExecRead(sql, para);
return myReader;
}
static internal IDataReader Get()
{
// E.g., returns all records
}
static internal IDataReader Save(Contact saveObject)
{
// Code to save the passed object to the db and return the new
// ContactID if this is a new contact
return Get(contactID); // look up the added/updated contact and
return it to the caller.
}
static internal void Delete(Contact deleteObject)
{
// code to delete the contact
}
static private string SQLSelect
{
get
{
string sql = "SELECT ContactID,
+ "Name "
+ "FROM Contact WHERE 1=1 ";
return sql;
}
}
}
The GUI only sees and accesses the Contact and ContactCollection classes.
This has given me a pretty flexible business layer, but as you can see
there's a fair amount of boiler plate code in there. Now, I realise that I
may have pretty much replicated the functionality of data sets. My question
is really whether or not I may have just generated a ot of extra work, and
would have been just as well off with just using data sets. Would they
offer any real advantages without sacrificing too much of the control I
meant to achieve by using the strategy outlined above? I'm fully aware of
the capabilities of the data sets to consume data from XML etc, but then I
could always code that capability into my existing classes, too.
TIA,
OyvindS