Command Object Use Case

Command Object Use Case

Old forum URL: forums.lhotka.net/forums/t/4982.aspx


Warren posted on Monday, June 16, 2008


I am looking for advice on BO design for some batch functionality I will be adding into a new winforms application.  I would like to create a solution that is similar to an method used in an existing non-csla, VB6 winforms application.


The non-csla application process is:

  1. A DB stored procedure is triggered which loads bank balance information from a flat file into a temporary database table and then validates each record.
  2. If no validation errors occurred, this same stored procedure copies the records from the temporary table into a permanent table which stores bank balance information then deletes all records from the temporary table.

  
In my new application, all database access is done via stored procedures, no in-line SQL statements are allowed.

I have 3 use cases for the bank balance information:

  1. Load Bank Balance Information.
  2. Edit Bank Balance Information. 
  3. Various other uses cases that need read only use of bank balance information.

For use cases 2 & 3 I am planning to create an Editable Root Object, Readonly Collection Object and ReadOnly Object.

After reading the book on pages 240-243 I think I should use a Command object for the Load Bank Balance use case. Most of the validation used in the current stored procedure is not business rules but is ensuring a date is valid and numbers are in valid numeric format. However, there is
some validation that searches other tables for existence of a related record.

My specific questions are:

1) Is the Load Bank Balance use case a good candidate for a Command Object?
2) Should the validation portion of the current stored procedure that searches for related records be moved out to a separate command object which implements exists functionality?

Any feedback is appreciated, thanks.

 


 

JoeFallon1 replied on Tuesday, June 17, 2008

IMO

#1 - No. This is not a good place for a Command Object.

I would actually tyr to re-use the Editable Root Object instead. It will have all of your validation rules for Bank Balance so if you try to load information from a file into a new instance then you will Know whether or not it IsValid right away and then you can also .Save it.

#2 - not sure what code is in the SP but I would just add validation rules to the Editable Root object and then cover all cases.

Joe

 

Warren replied on Tuesday, June 17, 2008

Hi Joe,

#1 - I can understand the benefits of using the business rules already in the business object to load the data but I thought that the code that finds the flat file and bulk loads it into the temporary table should be encapsulated in an object also, hence my idea of using a Command object to load this data.  

#2 - The code in the SP executes various "does record exists" calls. For example, a bank balance record contains information about the balance for an account at a particular bank. In order for the bank record to pass validation, I must make sure that the bank and account number already exists in the database. I thought this was a good  reason to develop two command objects BankExists and AccountExists.

 

 

JoeFallon1 replied on Tuesday, June 17, 2008

#1 - I agree that the code for locating and loading the flat file should be entriely separate. I use a Winforms app for this kind of code. But once the data is loaded in memory (usually in a datatable) then I simply new up an instacne of my root BO and load its properties with the data. Then I test if it IsValid and try to save it. If there are any issues, I log them and then loop back and do it again. So I catch any exceptions to ensure I have the chance to keep looping.

#2 - I agree completely that BankExist and AccountExists could be 2 command objects. But I would simply use them both in rules for my root BO. I also use rule priority of 1 for DB calls so that all other simple rules must first pass before we hit the DB.

Joe

 

stefan replied on Tuesday, June 17, 2008

Hi Warren,

the CSLA-way of doing what you want would be as follows (IMHO):

Create an editabe child object ('FileEntry') that represents one single entry in your file.
Create an editable child list (Of FileEntry), named 'MyFileData'.
Create an editable root parent object ('ProcessFileUseCase'), containing a MyFileData as a child object.

ProcessFileUseCase would be responsible for accessing the file system and loading the data contained in the file. You would pass the filename to the GetProcessFileUseCase factory method. That factory method would pass the filename to the DataPortal_Fetch method through the criteria object.

DataPortal_Fetch would make the file system access, and fill its MyFileData child list.
Note that if the application should run on an arbitrary client machine, what I suggest here only works with a remote DataPortal configured, because of the file system access from within the DataPortal!
Otherwise the DataPortal would have to call a service that would be running on the machine where the files are located...

Your FileEntry class would have validation rules for each presumable foreign key fields.
You will need a lookup-list class (NameValueListBase derived) for each foreign key you want to check. Make sure you use a cached list there! See the RoleList in the ProjectTracker example.
Then your validation rules would try to look up the value read from the file in these lists. If not found, the rule would be broken, and your ProcessFileUseCase object would refuse to save. Override IsValid therefore.

Then you could choose to further process the valid/invalid entries i.e. saving the valid ones to db and writing back the changes to the file...

Your command objects would trigger at least one database roundtrip per file entry.
Following my suggestion would only result in one hit per lookup list!

Hope that helps!


Stefan

SomeGuy replied on Tuesday, June 17, 2008

Assuming that this is a process that is only run once for the whole company, not different clients loading thier own data; I would stick to a process similar to what you have, and have most of the work done on the server and by the db server. You can use a Command object to kick off the process, by loading the temp db table (DTS?), and then calling the sproc that validates/imports the data. If you can do all the work in a sproc, do it!

I would reserve BO's for interactive user operations, like viewing/editing the invalid records to be fixed and imported manually.

Copyright (c) Marimer LLC