Nulls and Database objects

  • Thread starter Thread starter tshad
  • Start date Start date
T

tshad

I have people telling me that I should set up objects for my tables, but I
am finding the Null problem makes that difficult.

It isn't a big problem if you are not updating the table, but if you are -
it is a real problem if you have Nullable fields. You can't always use a 0
or -1 to tell whether a field is null and dates are another problem. I
don't want to use some obscure date in the future for something like
"EndDate" or "DateTerminated" where there is no ending date or an employee
hasn't been terminated yet.

You don't have a problem if you use a field on an asp.net screen, as an
empty field would be taken as null. But that is not the same in an object
where you have to define a value for your fields.

I can see some real advantages to using objects for my tables, but they seem
to be outweighed by being unable to handle the nulls in either vb.net or c#.

I'd be curious to know how others are handling this problem (without using 0
or 1 or obscure data).

The problem is not reading the data from the table, but when changes are
made and you need to write it back, you need to know when a field is
supposed to be Null.

Thanks,

Tom
 
You don't have a problem if you use a field on an asp.net screen, as an
empty field would be taken as null. But that is not the same in an object
where you have to define a value for your fields.

You do?
I can see some real advantages to using objects for my tables, but they seem
to be outweighed by being unable to handle the nulls in either vb.net or c#.

I'd be curious to know how others are handling this problem (without using 0
or 1 or obscure data).

The problem is not reading the data from the table, but when changes are
made and you need to write it back, you need to know when a field is
supposed to be Null.

I take it you are using simple data types for the "fields" on your objects.
If that's what you really want to do, you can define each private field as
"object" then cast it in the getter/setter. I don't know how big the
performance penalty is for "boxing" all those values, it'll certainly depend
on your application. We use objects to hold various information about our
"fields". We find it advantagous to be able to hold more information than
just the current value - for example the "old" value (as loaded from the
database), whether the field is loaded or not (some fields are lazy loaded),
and whether the field is null, among other things.

So, our code looks like this (method names reveal my Delphi background):

myObject.FirstName.AsString = "Scott";
myObject.LastName.AsString = "Roberts";
myObject.Salary.AsFloat = 250000.00; // haha!

I could also do:

myObject.Salary.AsString = SalaryEdit.Text; // conversion handled by
"AsString", handles "$", etc.
myObject.Salary.IsNull = true;

Just some ideas. Don't think that you're limited to:

private decimal _salary;
public decimal Salary
{
get {return _salary;}
set {_salary = value;}
}
 
Scott Roberts said:

Actually, what I do is check for null coming from the database or check to
see if my field (textbox or label) is blank if going to the database.

For non-strings (int, decimal, money, dates) this is how I have to handle
it.

If the data coming from the database is Null, I leave the field blank. Then
when I write the data back and the field is blank, I send DBNull.Value like
so:

if salaryDesired.text = ""
.Add("@salaryDesired",SqlDbType.Money).value = DBNull.Value
else
.Add("@salaryDesired",SqlDbType.Money).value =
Regex.Replace(salaryDesired.text,"\$|\,","")
end if

I can't do that in an object as there is now in intermediate step.

I get the data from the database, put the data into the Objects private
variables (which can't be null). I then do whatever I am going to do on the
page and would now need to move the data back to the Object (again can't be
null) and then the data is moved from the Objects private variables to the
database record.

How do you tell if a value was a Null when you put it back?
I take it you are using simple data types for the "fields" on your
objects.
If that's what you really want to do, you can define each private field as
"object" then cast it in the getter/setter. I don't know how big the
performance penalty is for "boxing" all those values, it'll certainly
depend
on your application. We use objects to hold various information about our
"fields". We find it advantagous to be able to hold more information than
just the current value - for example the "old" value (as loaded from the
database), whether the field is loaded or not (some fields are lazy
loaded),
and whether the field is null, among other things.

Keeping the old value would obviously be valuable. But do you do that for
all your fields?

For example, I have about 150 fields in one of my table records (mixture of
strings, ints, money and bits).

Do you set up each field as an object?
So, our code looks like this (method names reveal my Delphi background):

myObject.FirstName.AsString = "Scott";
myObject.LastName.AsString = "Roberts";
myObject.Salary.AsFloat = 250000.00; // haha!

Wouldn't that be nice. :)

I would do the same thing if I were setting up an object where the class
might be Position.

Then I would access my private variables as:

Position.FirstName = "Joe";
Position.Salary = 320000.00; // Thinking a little higher.

My class might be something like:
**********************************************
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using MyFunctions;

namespace FtsData
{
[Serializable]
public class Position
{
private int positionID = 0;
private string firstName = "";
private decimal Salary = 0;

public Position()
{
}

public Position(int PositionID)
{

}

public int AddRecord()
{
int rowsAffected = 0;
int iError = 0;
DbObject myDbObject = new DbObject();
SqlParameter[] parameters = {
new SqlParameter("@PositionID",SqlDbType.Int),
new SqlParameter("@FirstName",SqlDbType.VarChar,30),
new SqlParameter("@Salary",SqlDbType.Money) };

parameters[0].Value = positionID;
parameters[1].Value = firstName;
parameters[2].Value = salary;

try
{
iError = myDbObject.RunProcedure("AddPosition", parameters, ref
rowsAffected);
}
catch (SqlException sqle)
{
throw sqle;
}
}


// Properties

public int PositionID
{
get { return positionID; }
set { positionID = value; }
}

public string FirstName
{
get { return firstName; }
set { firstName = value; }
}

public decimal Salary
{
get { return salary; }
set { salary = value; }
}
}
}
***********************************************************************

Thanks,

Tom
 
i wrote a "NullHandler" class. By design, i decided for Value Types (int,
decimal, DataTime etc.) MaxValue indicates DBNull, for reference types, null
indicates DBNull.. when i get/set a value from/to database object
(DataReader, DataParameter etc.) i use NullHandler.. only boolean type cant
be null in my design. (because i didnt need. i hope you wont need too.)
here is the class.


using System;

namespace DataAccess

{

public sealed class NullHandler

{

private NullHandler()

{

}

public static void GetValueFromDbObject(object dbObjectValue, ref string
destination)

{

destination = dbObjectValue == DBNull.Value ? null : (string)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref int
destination)

{

destination = dbObjectValue == DBNull.Value ? int.MaxValue :
(int)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref decimal
destination)

{

destination = dbObjectValue == DBNull.Value ? decimal.MaxValue :
(decimal)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref DateTime
destination)

{

destination = dbObjectValue == DBNull.Value ? DateTime.MaxValue :
(DateTime)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref long
destination)

{

destination = dbObjectValue == DBNull.Value ? long.MaxValue :
(long)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref byte
destination)

{

destination = dbObjectValue == DBNull.Value ? byte.MaxValue :
(byte)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref object
destination, Type destinationType)

{

switch(destinationType.Name)

{

case "System.String" :

destination = dbObjectValue == DBNull.Value ? null : dbObjectValue;

break;

case "System.Int32" :

destination = dbObjectValue == DBNull.Value ? Int32.MaxValue :
dbObjectValue;

break;

case "System.Decimal" :

destination = dbObjectValue == DBNull.Value ? Decimal.MaxValue :
dbObjectValue;

break;

case "System.DateTime" :

destination = dbObjectValue == DBNull.Value ? DateTime.MaxValue :
dbObjectValue;

break;

case "System.Int64" :

destination = dbObjectValue == DBNull.Value ? Int64.MaxValue :
dbObjectValue;

break;

case "System.Byte" :

destination = dbObjectValue == DBNull.Value ? Byte.MaxValue : dbObjectValue;

break;

default :

if(destinationType.IsValueType)

throw new NotImplementedException("Converting from type '" +
dbObjectValue.GetType().Name + "' to '" + destinationType.Name + "' not
implemented..");

destination = dbObjectValue == DBNull.Value ? null : dbObjectValue;

break;

}

}

public static void SetDbObjectValueFromValue(string sourceValue, ref object
dbObjectValue)

{

if(sourceValue == null)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(int sourceValue, ref object
dbObjectValue)

{

if(sourceValue == int.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(decimal sourceValue, ref object
dbObjectValue)

{

if(sourceValue == decimal.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(DateTime sourceValue, ref
object dbObjectValue)

{

if(sourceValue == DateTime.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(long sourceValue, ref object
dbObjectValue)

{

if(sourceValue == long.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(byte sourceValue, ref object
dbObjectValue)

{

if(sourceValue == byte.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(object sourceValue, Type
sourceValueType, ref object dbObjectValue)

{

switch(sourceValueType.Name)

{

case "System.String" :

{

string val = (string)sourceValue;

if(val == null)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

case "System.Int32" :

{

int val = (int)sourceValue;

if(val == int.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}


case "System.Decimal" :

{

decimal val = (decimal)sourceValue;

if(val == decimal.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

case "System.DateTime" :

{

DateTime val = (DateTime)sourceValue;

if(val == DateTime.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

case "System.Int64" :

{

long val = (long)sourceValue;

if(val == long.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

case "System.Byte" :

{

byte val = (byte)sourceValue;

if(val == byte.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

default :

if(sourceValueType.IsValueType)

throw new NotImplementedException("Converting from type '" +
dbObjectValue.GetType().Name + "' to '" + sourceValueType.Name + "' not
implemented.");

if(sourceValue == null)

dbObjectValue = DBNull.Value;

else

sourceValue = sourceValue;

break;

} // End Switch Statment

} // End Method Block



}

}





Here is how i use this class :



protected override void DoLoad(IDataReader rd)

{

this.itemName = (string)rd["ItemName"];

NullHandler.GetValueFromDbObject(rd["Description"], ref this.description);

NullHandler.GetValueFromDbObject(rd["ItemGroupId"], ref this.itemGroupId);

}




protected override void AppendSaveParameters(DbParameterCollection paramCol)

{

paramCol.Add(
DataAccessHelper.ParameterHandler.GetInputParameterFromValue("ItemName",
itemName) );

paramCol.Add(
DataAccessHelper.ParameterHandler.GetInputParameterFromValue("Description",
description) );

paramCol.Add(
DataAccessHelper.ParameterHandler.GetInputParameterFromValue("ItemGroupId",
itemGroupId) );

}



DataAccessHelper's ParameterHandler property is a kind of factory -
singleton (DataAccessHelper instantinates a specific ParameterHandler based
on "DataProvider" value in the application settings. (for example it
instantinates SqlParameterHandler class written by me.), and returns this
single instance everytime a parameter handler is requested.) here is a
method of SqlParameterHandler :



IDataParameter
DataAccess.Interfaces.IDbParameterHandler.GetInputParameterFromValue(string
paramName, byte value)

{

IDataParameter param = new SqlParameter("@" + paramName, SqlDbType.TinyInt);

object obj = null;

NullHandler.SetDbObjectValueFromValue(value, ref obj);

param.Value = obj;

return param;

}





Hope this helps.. you can ask further.
 
tshad said:
if salaryDesired.text = ""
.Add("@salaryDesired",SqlDbType.Money).value = DBNull.Value
else
.Add("@salaryDesired",SqlDbType.Money).value =
Regex.Replace(salaryDesired.text,"\$|\,","")
end if

I can't do that in an object as there is now in intermediate step.

Sure you can. It's the GUI's responsibility to set the business object
properties correctly. It's the BO's responsibility to persist the data
correctly.

if salaryDesired.Text = string.Empty
myObject.salaryDesired.IsNull = true;
else
myObject.salaryDesired.AsString = salaryDesired.Text;
I get the data from the database, put the data into the Objects private
variables (which can't be null).

Sure they can, if they are of type "object".
Keeping the old value would obviously be valuable. But do you do that for
all your fields?

Yes. It's how I know if a particular field needs to be persisted to the
database or not. I don't write fields to the DB that didn't change.
For example, I have about 150 fields in one of my table records (mixture of
strings, ints, money and bits).

So? Are you writing an application for devices with limited memory? If so,
that makes a difference.
Do you set up each field as an object?

Yes.
 
So? Are you writing an application for devices with limited memory? If so,
that makes a difference.

how about if you are writing a multi-client app like a web app? then it
makes difference.

and one thing about keeping old values : do you use dynamic sql? if not, how
do you send parameters (only changed fields)
 
This looks good. I assume this is similar to what Scott was talking about.

2 questions.

1. I have never used the Object type. Is it defined somewhere or is it
like a variant type that contains any type of data? I assumed that was the
case as you move any type of data into it.

2. How would you handle data that happened to be the Max Value of that
particular type?

For example, I assume that the MaxValue for byte is 255. I can see that
hitting the max value for decimal or long would be rare, but I can
definately see using 255 for a byte.

Thanks,

Tom

The Crow said:
i wrote a "NullHandler" class. By design, i decided for Value Types (int,
decimal, DataTime etc.) MaxValue indicates DBNull, for reference types,
null indicates DBNull.. when i get/set a value from/to database object
(DataReader, DataParameter etc.) i use NullHandler.. only boolean type cant
be null in my design. (because i didnt need. i hope you wont need too.)
here is the class.


using System;

namespace DataAccess

{

public sealed class NullHandler

{

private NullHandler()

{

}

public static void GetValueFromDbObject(object dbObjectValue, ref string
destination)

{

destination = dbObjectValue == DBNull.Value ? null :
(string)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref int
destination)

{

destination = dbObjectValue == DBNull.Value ? int.MaxValue :
(int)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref decimal
destination)

{

destination = dbObjectValue == DBNull.Value ? decimal.MaxValue :
(decimal)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref DateTime
destination)

{

destination = dbObjectValue == DBNull.Value ? DateTime.MaxValue :
(DateTime)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref long
destination)

{

destination = dbObjectValue == DBNull.Value ? long.MaxValue :
(long)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref byte
destination)

{

destination = dbObjectValue == DBNull.Value ? byte.MaxValue :
(byte)dbObjectValue;

}

public static void GetValueFromDbObject(object dbObjectValue, ref object
destination, Type destinationType)

{

switch(destinationType.Name)

{

case "System.String" :

destination = dbObjectValue == DBNull.Value ? null : dbObjectValue;

break;

case "System.Int32" :

destination = dbObjectValue == DBNull.Value ? Int32.MaxValue :
dbObjectValue;

break;

case "System.Decimal" :

destination = dbObjectValue == DBNull.Value ? Decimal.MaxValue :
dbObjectValue;

break;

case "System.DateTime" :

destination = dbObjectValue == DBNull.Value ? DateTime.MaxValue :
dbObjectValue;

break;

case "System.Int64" :

destination = dbObjectValue == DBNull.Value ? Int64.MaxValue :
dbObjectValue;

break;

case "System.Byte" :

destination = dbObjectValue == DBNull.Value ? Byte.MaxValue :
dbObjectValue;

break;

default :

if(destinationType.IsValueType)

throw new NotImplementedException("Converting from type '" +
dbObjectValue.GetType().Name + "' to '" + destinationType.Name + "' not
implemented..");

destination = dbObjectValue == DBNull.Value ? null : dbObjectValue;

break;

}

}

public static void SetDbObjectValueFromValue(string sourceValue, ref
object dbObjectValue)

{

if(sourceValue == null)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(int sourceValue, ref object
dbObjectValue)

{

if(sourceValue == int.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(decimal sourceValue, ref
object dbObjectValue)

{

if(sourceValue == decimal.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(DateTime sourceValue, ref
object dbObjectValue)

{

if(sourceValue == DateTime.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(long sourceValue, ref object
dbObjectValue)

{

if(sourceValue == long.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(byte sourceValue, ref object
dbObjectValue)

{

if(sourceValue == byte.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = sourceValue;

}

public static void SetDbObjectValueFromValue(object sourceValue, Type
sourceValueType, ref object dbObjectValue)

{

switch(sourceValueType.Name)

{

case "System.String" :

{

string val = (string)sourceValue;

if(val == null)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

case "System.Int32" :

{

int val = (int)sourceValue;

if(val == int.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}


case "System.Decimal" :

{

decimal val = (decimal)sourceValue;

if(val == decimal.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

case "System.DateTime" :

{

DateTime val = (DateTime)sourceValue;

if(val == DateTime.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

case "System.Int64" :

{

long val = (long)sourceValue;

if(val == long.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

case "System.Byte" :

{

byte val = (byte)sourceValue;

if(val == byte.MaxValue)

dbObjectValue = DBNull.Value;

else

dbObjectValue = val;

break;

}

default :

if(sourceValueType.IsValueType)

throw new NotImplementedException("Converting from type '" +
dbObjectValue.GetType().Name + "' to '" + sourceValueType.Name + "' not
implemented.");

if(sourceValue == null)

dbObjectValue = DBNull.Value;

else

sourceValue = sourceValue;

break;

} // End Switch Statment

} // End Method Block



}

}





Here is how i use this class :



protected override void DoLoad(IDataReader rd)

{

this.itemName = (string)rd["ItemName"];

NullHandler.GetValueFromDbObject(rd["Description"], ref this.description);

NullHandler.GetValueFromDbObject(rd["ItemGroupId"], ref this.itemGroupId);

}




protected override void AppendSaveParameters(DbParameterCollection
paramCol)

{

paramCol.Add(
DataAccessHelper.ParameterHandler.GetInputParameterFromValue("ItemName",
itemName) );

paramCol.Add(
DataAccessHelper.ParameterHandler.GetInputParameterFromValue("Description",
description) );

paramCol.Add(
DataAccessHelper.ParameterHandler.GetInputParameterFromValue("ItemGroupId",
itemGroupId) );

}



DataAccessHelper's ParameterHandler property is a kind of factory -
singleton (DataAccessHelper instantinates a specific ParameterHandler
based on "DataProvider" value in the application settings. (for example it
instantinates SqlParameterHandler class written by me.), and returns this
single instance everytime a parameter handler is requested.) here is a
method of SqlParameterHandler :



IDataParameter
DataAccess.Interfaces.IDbParameterHandler.GetInputParameterFromValue(string
paramName, byte value)

{

IDataParameter param = new SqlParameter("@" + paramName,
SqlDbType.TinyInt);

object obj = null;

NullHandler.SetDbObjectValueFromValue(value, ref obj);

param.Value = obj;

return param;

}





Hope this helps.. you can ask further.
 
This looks good. I assume this is similar to what Scott was talking
about.

2 questions.

1. I have never used the Object type. Is it defined somewhere or is it
like a variant type that contains any type of data? I assumed that was
the case as you move any type of data into it.

actually, i didnt ever used object type overload. i wrote it just for case,
when i didnt wrote an overload for a type. but in my project, i didnt needed
that method yet.
2. How would you handle data that happened to be the Max Value of that
particular type?

For example, I assume that the MaxValue for byte is 255. I can see that
hitting the max value for decimal or long would be rare, but I can
definately see using 255 for a byte.

this made me think too, but i didnt needed the value "255" for any byte
field too. but if i would need, it shows byte data type is not big enough
for that data, because when i werent used null handler and byte type, after
using 255, 256 wont be possible too. so think 254 is your limit for byte,
rather then 255. but if there is a real deal (for example you have to deal a
value that comes from a part of computer system), you can choose not using
NullHandler for that particular field and acces it directly.
 
The Crow said:
do you think its good? did u measure performance?

I assume you are referring to the ability of most DBs to cache execution
plans and reuse them if the same SQL statment is issued multiple times.

There are trade-offs to every decision. We are aware of the above fact
(applies to SQL Server and Oracle for sure) and decided to go with dynamic
SQL anyway. The advantages we see are:

1. Concurrency ("last save wins" is sufficient for us if only changed fields
are saved).
2. Less DB access (no SQL generated at all if no fields changed, regardless
of how many times the user clicks "Save")
3. Smaller SQL commands (if only 1 of 150 fields changed, the SQL generated
is very small).
4. For batch operations, it's always the same field(s) changing so the same
3 or 4 SQL statments will be dynamically generated and statement caching is
effective.
 
I am looking at the Crow's class and like how it's done.

But that one also uses a one dimensioned simple variant type of data to hold
the value.

How would you change my class to have old values and a field to hold whether
it is null or not?

Would you set it up a multidimension variable or as a complex type of
object/structure?

I am just trying to look at different possibilities before going too much
farther with my objects if there is (and I am sure there is) a better way to
handle it and then have to reprogram it later.

Thanks,

Tom
My class might be something like:
**********************************************
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using MyFunctions;

namespace FtsData
{
[Serializable]
public class Position
{
private int positionID = 0;
private string firstName = "";
private decimal Salary = 0;

public Position()
{
}

public Position(int PositionID)
{

}

public int AddRecord()
{
int rowsAffected = 0;
int iError = 0;
DbObject myDbObject = new DbObject();
SqlParameter[] parameters = {
new SqlParameter("@PositionID",SqlDbType.Int),
new SqlParameter("@FirstName",SqlDbType.VarChar,30),
new SqlParameter("@Salary",SqlDbType.Money) };

parameters[0].Value = positionID;
parameters[1].Value = firstName;
parameters[2].Value = salary;

try
{
iError = myDbObject.RunProcedure("AddPosition", parameters, ref
rowsAffected);
}
catch (SqlException sqle)
{
throw sqle;
}
}


// Properties

public int PositionID
{
get { return positionID; }
set { positionID = value; }
}

public string FirstName
{
get { return firstName; }
set { firstName = value; }
}

public decimal Salary
{
get { return salary; }
set { salary = value; }
}
}
}
***********************************************************************

Thanks,

Tom
I could also do:

myObject.Salary.AsString = SalaryEdit.Text; // conversion handled by
"AsString", handles "$", etc.
myObject.Salary.IsNull = true;

Just some ideas. Don't think that you're limited to:

private decimal _salary;
public decimal Salary
{
get {return _salary;}
set {_salary = value;}
}
 
How would you change my class to have old values and a field to hold whether
it is null or not?

Would you set it up a multidimension variable or as a complex type of
object/structure?

Basically, we have a SBSFieldList class (just a wrapper around ArrayList
with some convenience methods) that holds a list of "SBSField" objects (or
objects derived from SBSField - e.g. SBSStringField).

public class MyClass
{
MyFieldListClass _fields = new MyFieldListClass();

public MyClass()
{
// Fill _fields with field objects.
}

public SBSStringField FirstName
{
get {return _fields.FieldByName("firstname");}
}
}

And you access the property like this:

myObject.FirstName.AsString = "Scott";
myObject.FirstName.IsNull = true; // Set the first name to null value.

Note: We don't actually do "FieldByName" and scan the list for the proper
field object every time you access a property, that would be slow. There are
integer array indexes stored for each property to speed things up, but this
is simpler for demo purposes. And you'd really want the field list defined
in a base class and populated by the derived classes. This allows the base
class to have access to the fields without the need for reflection, etc.
 
Still a little confused on what you are doing.

But it is probably a little more that I can do at the moment.

Thanks,

Tom
 

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

Back
Top