× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



Walden H. Leverich wrote:
That's not far off, save two things. First, we generate our classes,
saves us writing all the grunt-code. Second, we've got a single base
class that does the IO. So a class would look something like:

[DatabaseTable("Customer")]
class Customer : BusinessObject {

//define some private fields
[DatabaseField("CustomerId", IsKey=true, OmitFromInsert=true)]
int _customerId;

[DatabaseField("CustomerName", Length=100)]
string _customerName;

[DatabaseField("AddressLine1", Length=100)]
String _address1;

[DatabaseField("LastOrderDate")]
DateTime? _lastOrderDate;

//define some properties
public int CustomerID {
get {return _customerId;}
}
public string Name {
get {EnsureLoaded(); return _customerName;}
set {SetField("_customerName", value);}
}
public string AddressLine1{
get {EnsureLoaded(); return _ AddressLine1;}
set {SetField("_AddressLine1", value);}
}
public DateTime? LastOrderDate {
get {EnsureLoaded(); return _ LastOrderDate;}
set {SetField("_LastOrderDate ", value);}
}

//And define the factory methods
public static Customer GetCustomer(int CustomerId)
{
Customer c = new Customer();
c.LoadFromDB(CustomerId);
return c;
}

public static Customer NewCustomer()
{
return new Customer();
}
}

It appears you allow for a field configuration to be declared? DatabaseField("CustomerId", IsKey=true, OmitFromInsert=true) I assume this tells the BaseBusinessObject that there is a database field that is a key and omit it when generating an insert because it's an identify field?

What we have done is expand this concept to include many configurable field attributes and intelligent DatabaseFields such as "SocialSecurityField", ZipCodeField, AreaCodeField, CreditCardNumberField which all inherit from a base FIELD object instead of using standard datatypes such as Strings and ints. This allows for automatic validation in many cases. For example, when the user enters a social security value, into a business object it can be auto validated before the insert or update. So a businessObject has a collection or list of intelligent fields.

This is where we have seen a lot of value in inheritance although it tends to be very shallow inheritance. For example: We have a Field base class with a StringField subclass further subclassed by ZipCodeField and SocialSecurityField. Each field is soft coded for easy configuration to include things like: a) is the field required? b) length, concurrency rules, possible values (pick list) c) Security (who is authorized to view it or edit it. d) key position e) associations to other tables etc....

We are then able to create UI generators that given a "businessObject" are able to dynamically generate a "HTML" interface appropriate for that object including field sizes, required field attributes, picklists, security, etc. NOTE: The business code and UI are separate but the UI code has a consistent model to discover how the UI should be rendered based on the business rules. For example, if a field is required, then we want a red marker indicated to the user that they must fill it in. All database CRUD operations are then automatically enabled without generating any code. When a insert operation runs, it can generically extract all UI input, generically validate basic business rules such as required fields, SSN's, zipcode lengths, etc. This is done by the base business object looping through it's contained fields and asking each to validate themselves (this uses polymorphism) I.E. A SSNFIELD overrides the "validate" method and checks it's data. This leaves the programmer only needing to program for the exception cases.











For us that's a complete definition of a customer. The customer object
inherits a ton of stuff from BusinessObject, not the least of which are
the methods LoadFromDB, EnsureLoaded, SetField and Save.

LoadFromDB looks up the customer in the Customer table (from the
DatabaseTable attribute) and loads up the data, it's overloaded to
handle single and multiple-key tables.


I understand but how do you allow the programmer to specify what fields they want included in their "ghost" or SKINNY object? If I say "Customer.GetCustomer(12345);" how many fields do I get? As you know many files can have hundreds of fields and bring back too many (for a subfile) hurts performance.

What we did here is actually leverage the power of SQL something like:

SQLContext sql = new SQLContext("CONNECTION POOL NAME");
sql.setSQL("select a, b, c, d from lib.table where state = "CA"");
sql.setRowCount(100); // page by 100
sql.setBusinessObject(Customer.class); // optional only needed for special coding is used
sql.setCache(true);

RowCollection rows = DataEngine.getRows(sql);



This allows us to specify what fields to return from what table. Resultset Metadata is used to discover the fields and identify what their field configuration data is. If field b is a social security number then a SSNFIeld is created. The generic "Row" business object holds all the fields. Row instances are stored in a generic "RowCollection".






EnsureLoaded makes sure we're not
looking at a "ghost" object, which is a concept we support to delay-load
an object, if it's a ghost is LoadFromDB's it.

We call this the fly weight pattern. Initial subfile list only contains fields needed for list view but then you can "fill up" the object by running a SQL to retrieve all fields by key value.



SetField actually sets
the member fields with the new values, but also checks that strings,
byte arrays etc. aren't too long (Length on the DatabaseField
attribute), and maintains a list of changed fields.



Here is where we actually check basic business data such as SSN, zip, area codes, etc as well. We also check if an updated field value is really different than the previous and if it is set to not allow concurrent updates, it gets built into the SQL update (optimistic locking)




And Save would
actually save changes (or insert a new row) into the customer table.
Only columns that have changed (and key columns) are included in the IO
requests (hence the list of changed columns).

We would consume this via:

Customer myCustomer = Customer.GetCustomer(12345);
myCustomer.Name = "Walden";
myCustomer.AddressLine1 = "123 Main st;
myCystomer.Save();

-or-

Customer myCustomer = Customer.NewCustomer();
myCustomer.Name = "Paul";
myCustomer.Save();
Console.WriteLine("New customer Id is: {0}", myCustomer.CustomerId);


What if the addressLine1 was required before save? I.E, it is a required field and the user failed to put a value in it.


I can see a lot of effort has went into your framework and the value it gives you and I understand many of the challenges.

The most beneficial technique for us was to stop with the static buiness object approach and utilize a dynamic business object with a collection of intelligent fields. This does very much allow for inheritance of business objects (both at a individual Field level as well as a businessObject level. Our goal all along was productivity and with this technique and design pattern, we are able to create simple to fairly robust web applications with zero coding or code generation. In any case with certain qualifications I am a firm believer in OO inheritance. Anyway ... my .02 Thanks, Paul Holm




As an Amazon Associate we earn from qualifying purchases.

This thread ...

Replies:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.