{
TdmoProject Object }
{-------------------------------------------------}
constructor TdmoProject.Create(aOwner : TObject);
begin
inherited Create(aOwner);
end;
procedure TdmoProject.FreeChildren;
begin
// The
FreeChildren method will free all child classes of TdmoProject
// but we have to actually set the private variable back to Nil!
inherited FreeChildren;
FTasks := Nil;
end;
destructor TdmoProject.Destroy;
begin
inherited Destroy;
end;
procedure TdmoProject.Save;
var iTxnId : Integer;
begin
// We need to
manage the db transaction ourselves, start the transaction
// and get the iTxnId representing this Transaction (only the dbCommit
with
// the correct transaction id will actually perform the db COMMIT).
Database.dbStart(iTxnId);
try
inherited Save; //
Perform the save on the project
// We reference FTasks to save them (not Tasks to
make sure we do not invoke GetTasks)
if FTasks <> Nil
then // Ensure the linkage value is seeded into the child class...
begin
// All Tasks need to be linked back to this Project
FTasks.SetFieldValue(nctaskProjectId, IntToStr(ProjectId));
FTasks.Save; //
Saves all Modified tasks
end;
Database.dbCommit(iTxnId); //
If all is well so far, we perform a DB COMMIT
except on E:Exception do
begin
Database.dbRollback; //
Anything goes wrong we perform a rollback
raise EShowError.Create('Error saving
TdmoProject...'#10#13 + E.Message);
end;
end;
// At the end of the Save method, the RecordStates of all project and task
// records will have been set back to rsFetched from either rsInsert,
rsUpdate
// or rsDelete.
// If a task was physically deleted, the FTasks dataset will be less one
entry.
// The Database.dbCommit calls the inherited Reset method of all saved
records
// to have them reset their RecordStates OR destroy themselves if deleted.
end;
function TdmoProject.RemoveTask(aTask :
TdmoTask) : Boolean;
begin
Result := False;
if (Tasks.FindRecord(aTask)) then
// Look for this task in the list
begin
Tasks.MarkForDelete(Tasks.Current); //
Mark it for deletion on the next Save Op!
Result := True;
end;
end;
procedure TdmoProject.RefreshTasks;
begin
FTasks.Free;
FTasks := Nil;
end;
function TdmoProject.AddTask(aTaskName :
string) : TdmoTask;
begin
// This method is
stating that task names must be unique
// We return the task if found or if marked for deletion,
// otherwise, we create a new task record and specify some
// initial values!
if (Tasks.FindByString(nctaskTaskName,
aTaskName)) then
Result := Tasks.Current
else if (Tasks.PendingDelete(nctaskTaskName,
aTaskName)) then
begin
Result := Tasks.Current;
Result.Cancel;
end
else
begin
Result := Tasks.New;
Result.ProjectId := Self.ProjectId;
Result.TaskName := aTaskName;
end;
end;
function
TdmoProject.GetTasks : TdmoTaskDataSet;
begin
// Create the FTasks dataset if not already done
so...
if
FTasks = Nil then
FTasks := TdmoTaskDataSet.Create(Self);
// Only perform the database query to load the tasks if we have a project
id
// and if the tasks are not already cached (i.e. loaded)
if (ProjectId > 0) and
(not FTasks.Cached) then
begin
FTasks.Filters.Clear;
FTasks.AddIntFilter(loAnd, nctaskProjectId, opEq, ProjectId, True);
// WHERE task.project_id=NNN
FTasks.Load; // performs
the SQL Select and creates one entry per task record
end;
Result := FTasks; // That SIMPLE!!!
end;
function TdmoProject.TableClass : TtscTableDefListClass;
begin
// TableClass is
invoked within DataSet and Record Constructors
// It is what specifies the database tables for this object!
Result := TdmoProjectTableDefs; //
IMPORTANT : References the appropriate Project tables and field
definitions
end;
function TdmoProject.GetFieldName(ix : integer) :
string;
begin
// Maybe
TdmoProject was derived from some other Project class
Result := inherited GetFieldName(ix);
// It wasn't, so the following case will convert the
property Index to a fieldname constant
function
TdmoProject.GetProjectStatusCd : String;
begin
Result := FieldByName(ncprojProjectStatusCd).AsString;
end;
procedure
TdmoProject.SetProjectStatusCd(aValue :
String);
begin
if FieldByName(ncprojProjectStatusCd).AsString
<> aValue then
begin
// Lookup the
field for the ProjectStatusCd and set its value!
// This will set the Modified flag for the record and change
// the RecordState from rsFetched to rsUpdate!
FieldByName(ncprojProjectStatusCd).AsString := aValue;
// The reason we made this method was to add some
intelligence...
if (aValue = 'CLOS') then // Project is being
CLOSED ?
ActualEndDate := Now;
end;
end;
{ TdmoProjectcmp Component }
{----------------------------------------------------------}
constructor TdmoProjectcmp.Create(aOwner : TComponent);
begin
inherited Create(aOwner);
end;
destructor TdmoProjectcmp.Destroy;
begin
inherited Destroy;
end;
//
GetTasks redirects down to the Data or Project Record
function TdmoProjectcmp.GetTasks : TdmoTaskDataSet;
begin
Result := Data.GetTasks;
end;
function TdmoProjectcmp.RecordClass : TtscDbRecordClass;
begin
Result := TdmoProject; // What does
this component wrapper create for records
end;
function TdmoProjectcmp.Data : TdmoProject;
begin
// Caste the DataRec to the TdmoProject so
application code does not need to.
//
Wrapper for the ProjectDataSet object is just a convenience to have
components
//
within the Delphi IDE that reference our objects!
{ TdmoProjectDataSetcmp Component }
{--------------------------------------------------}
constructor TdmoProjectDataSetcmp.Create(aOwner : TComponent);
begin
inherited Create(aOwner);
end;
destructor TdmoProjectDataSetcmp.Destroy;
begin
inherited Destroy;
end;
function TdmoProjectDataSetcmp.ListClass : TtscDataSetClass;
begin
Result := TdmoProjectDataSet;
end;
function TdmoProjectDataSetcmp.Current : TdmoProject;
begin
Result := TdmoProject(GetCurrentRecord);
end;
function TdmoProjectDataSetcmp.New : TdmoProject;
begin
Result := TdmoProject(GetNewRecord);
end;