Let's put our heads together...

Let's put our heads together...

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


SonOfPirate posted on Wednesday, January 24, 2007

I'm interested in getting ideas on how to implement a variation on the ProjectTracker Project-Resource-Assignment design to satisfy our current needs.

Just like ProjectTracker, we have a list of Assignments that belong to our Project object.  Each Assignment defines the Resource and its Role.  So far so good.  Our web app displays the list of current Assignments when the parent Project is shown.  The Add Assignment form has a drop-down list for Resources and another for Roles.  Both are data-bound using a CslaDataSource.

Each Resource is really a user in the application and has a list of Roles that they belong to (they can only be assigned to these Roles).  Because of this, we post the page back to the server and handle the Resource drop-down list's SelectedIndexChanged event to rebind the Roles drop-down list to the selected Resource's RoleList.

This is pretty straight-forward so far, but here's the catch: we are only allowed to assign a Resource once per Project and only one Resource can be in a given Role within the Project.

So this means is that we need to filter the Resources drop-down list to only include users that have not already been assigned to the project.  In addition, we have to eliminate users that don't belong to an unassigned Role.  Then, when we bind the Role drop-down list, we have to filter out any Roles that have already been assigned.

To further complicate matters, we have been told that we may need to restrict the number of times a particular user may be assigned to a project.  For instance, they may restrict Account Managers to only 10 projects at any one time.

All of that said, I'm looking for a hearty brainstorming session from all discussing how we may approach some complex logic such as this.  Thanks in advance to all who chime in.

Wink [;)]

 

 

Q Johnson replied on Thursday, January 25, 2007

SonOfPirate:

This is pretty straight-forward so far, but here's the catch: we are only allowed to assign a Resource once per Project and only one Resource can be in a given Role within the Project.

So this means is that we need to filter the Resources drop-down list to only include users that have not already been assigned to the project. 

Filtering a drop down list is a well understood concept here.  So I assume you are looking for help with a strategy for populating the list.  It would seem that you just need DataPortal_Fetch code that does a "missing items" type of query (i.e., something like SELECT Resources.ResourceID, Resources.Name FROM Resources LEFT JOIN ProjectResources on Resources.ResourceID = ProjectResources.ResourceID WHERE ProjectResources.Project = @ProjectID And ProjectResources.ResourceID Is NULL

SonOfPirate:

In addition, we have to eliminate users that don't belong to an unassigned Role.  Then, when we bind the Role drop-down list, we have to filter out any Roles that have already been assigned.

Same issue, isn't it?

SonOfPirate:

To further complicate matters, we have been told that we may need to restrict the number of times a particular user may be assigned to a project.  For instance, they may restrict Account Managers to only 10 projects at any one time.

Restricting the number could be an issue at selection time or assignment time.  Do you need to limit your list of Resources (from which the selection is made) to those with less than ten assignments?  Or would showing everybody in the list and trapping an assignment attempt that tries to make number eleven be acceptable?

 

SonOfPirate replied on Thursday, January 25, 2007

Getting the initial list of Resources using the type of SQL statement you described will work fine; however, we need to update the drop-down list each time an assignment is created without retrieving the list from the db because the change is not persisted at that time.  So, the user can add several assignments before the data is persisted back to the data store.

As for the last point, the requirements that have been conveyed thus far is that we should not display any resource that has already been max-ed out.  We will still have to trap an assignment attempt when the data is persisted if it causes the resource to go past the limit because it is a multi-user app with delayed persistance.

My initial thoughts are to have a Resource BO and ResourceCollection that is populated using the same type of select statement you described.  Then, in the event handler where we create the Assignment BO and add it to the Project BO, we would remove that Resource from the drop-down list explicitly (i.e. do not re-bind it).  The opposite for any Assignment that is removed - we would add that Resource back into the list.

We would have a Role BO and RoleCollection BO that is created and populated each time the SelectedIndexChanged event fires for the Resource's drop-down list.  We would have a similar select statement to pre-filter the result set from the db but would have to post-filter the list based on the current Assignments (since it's possible that some have not yet been persisted to the db).

Question is whether the removal/addition of the Resource upon assignment and filtering of the roles is something that should be done in the BO's or in the UI event handlers?  I am leaning towards embedding the logic within the BO's.  But this would require knowledge of each other in the BO.

For instance, when we add an assignment, we use the Project's AddAssignment(resourceID, roleID) method.  We could, in theory, remove the resource from the list of resources used for the drop-down list but this would require us to have a reference to that collection available to the Project object.  How?  An UnassignedResources child collection?

We were going to have the RoleCollection as a root collection that accepts the Resource/User's id value as a parameter in the factory method / stored procedure so that the proper pre-filtering can be done in SQL.  However, to allow the post-filtering to be done based on what roles have already been assigned, the RoleCollection would also need to have a reference to the Project.

See where the dilemma/confusion/complication comes in?

 

david.wendelken replied on Thursday, January 25, 2007

SonOfPirate:

Getting the initial list of Resources using the type of SQL statement you described will work fine; however, we need to update the drop-down list each time an assignment is created without retrieving the list from the db because the change is not persisted at that time.  So, the user can add several assignments before the data is persisted back to the data store.

...

My initial thoughts are to have a Resource BO and ResourceCollection that is populated using the same type of select statement you described. 

I think the names of objects are very important.  The right name focuses our thinking on the right data and behavior to accomplish its purpose. 

So, I do not think we are talking about Resource and ResourceCollection objects.  We are talking about a ValidProjectResourceChoice and a ValidProjectResourceChoiceCollection.

Ok, those are horribly long names, but I think they accurately reflect what they represent based upon your discussion. :)

As such, they do not have a life of their own (like a Resource that would exist whether the project existed or not).  In effect, they seem to be child objects within the Project.

If that is true, then it's perfectly appropriate for the Project (or Assignment?) object to add/remove items from the list. 

That said, I suspect that, under the hood, ValidProjectResourceChoice and  ValidProjectResourceChoiceCollection might really be project-specific filters on Resource and ResourceCollection.   But it would still make sense to me that adding/subtracting a resource to a project would cause the project's valid list of resource choices to change.

SonOfPirate:

See where the dilemma/confusion/complication comes in?

Sure do.  I'm not claiming to be an OO expert, so take my advice with a grain of salt. :)

SonOfPirate replied on Thursday, January 25, 2007

David, I'm right there with you.  Ironic that you made these points as this is exactly what I was wrestling with this afternoon.

Things are actually a bit more complicated for us in that there are multiple objects that have this behavior (and data).  Our Customer BO's behave the same way, for instance.  And, part of our requirements is that the resources assigned to the customer are inherited (in a non-OOP sense) by the project when created.  (Logically a Project can't exist without a Customer and there is a one-to-many relationship between them).  So, you are correct that a simple Resource object won't cut it - or maybe it will...

I was heading down the same thought path as you with regards to the collection of available or unassigned resources possibly being a child collection of these objects; afterall, it is within the context of the Customer or Project that these collections are defined.

So, now I am looking at having an editable child UnassignedResourceCollection of Resource objects for each BO as well as an editable child UnassignedRoleCollection (of Role objects).  Since neither the resource nor the role have a direct relationship back to the Customer or Project BO, I don't think it is necessary to differentiate them (i.e. CustomerResource, ProjectResource, etc) - but that may change as I move forward.  I also don't think that from the Resource's perspective it matters if it has been assigned or not.  It either exists in the list of assignments or in the list of unassigned resources.

In the AddAssignment(resourceID, roleID) method in the parent BO(s), I can easily remove the assigned objects from each child collection.  The UI can be re-bound and it sounds like all will be good.  To complete the picture, I would have a RemoveAssignment(assignmentID) method that would remove the Assignment object from that child collection and add the resource and role back into the UnassignedResources and UnassignedRoles collections, respectively.

Sound like I'm on the right track?

Only logic I still have to work out is where the data for the Roles drop-down list is coming from.  This is not bound to the UnassignedRoles collection directly.  Instead it is the intersection of the selected Resource's roles and the UnassignedRoles collection.  For example, if the selected Resource (user) is only assigned the "Account Manager" role but both the "Account Manager" and "Sales Manager" roles are unassigned, we would only want to display the "Account Manager" in the UI as this is the only one that resource can be assigned to.  Any ideas on this part?

Oh yea, and I forgot that this works the other way too.  When also don't want to show any resource that can't be assigned to any of the unassigned roles.  So, if we assigned that resource above to the "Account Manager" role for the Project, any other resource that can only be an "Account Manager" should also be removed from the list.

I think I could handle this in the AddAssignment method by iterating through all of the resources in the collection and checking if they have any roles still included in the UnassignedRoles collection.  BUT, adding them back in when an assignment is removed appears to be the challenge.

Time for more thought.

 

Copyright (c) Marimer LLC