Monday, February 25, 2008

Microsoft Project 2003 to 2007 Migration Workbench Part II

Part I of my discussion about migrating from Microsoft Project 2003 to 2007 talked mostly about the various maps and caches I use to move custom field list data from 2003 to 2007, as well as a sort of late-bound mapping of task data from a 2003 task to an 2007 task.   Before I proceed with the discussion, it occurred to me that I overlooked a major requirement for the migration process:  Learn everything I possibly can about the PSI.  There are easier and more efficient migration strategies than doing a task-by-task analysis and transformation from 2003 to 2007, but then I won't learn anything about the PSI and Project's client-side object model (I haven't done any Project automation since my days as technical product manager for Project 98 (ten years ago?!)).

Anyway, onto our migration discussion.

As I mentioned in Part I, we have a single MPP that houses a variety of activity types and each activity has a different schema.  For example, the Holiday type only has three components: Holiday Name, Start Date, and Duration, whilst the schema for a Onsite Training engagement includes Client, Trainer, City, Country, and about ten other components.  Rather than mixing activity types in Project 2007, we have created a number of distinct project in which tasks from the 2003 MPP will be partitioned during migration.  This implies another mapping problem.  Which task fields' data should be copy/updated into the new Project 2007 implementation and into which Project?   I created a simple (and not normalized) table in the database I created that houses all of my migration maps called  WiseConnectTaskComponent, and it looks like this:


     The table is not normalized because it is really optimized for fast lookups as I iterate through the tasks in the 2003 MP and I only reach out to SQL server for the map once in the very beginning of the migration pass.  Each 2003 MPP task has an event type that (for the most part) corresponds to a ProjectGuid in the table above.  For each relevant field (remember, each event type's task schema is different), there exists a corresponding Project2007FieldIdentifier.  Note that "FieldName" is not used in the 2007 column name because the value of the attribute can either contain a field GUID or a field name.  If you skip to the last column "Type", you will see a number present which is actually a bit field:


Go here an article on the Flags attribute.  The task components that have a value of 0 (zero) are built in fields so the data is copied/updated from the 2003 task to the 2007 task like this:


The only interesting thing about this code is the use of Enum.Parse.

For those task component maps that have a value other than zero, the value is a bit field indicating that it is a Custom field with the type of custom field type bit also set.  For each task in the 2003 MPP, I can look up the corresponding 2007 project it belongs to, analyze the fields (as mentioned in Part I) to ensure all of the enterprise custom field values are present, and then map the 2003 task to the 2007 task by looking at the type of field it is an setting the appropriate fields on the ProjectDataSet.TaskCustomFieldsRow object:    


Notice for TaskComponentType.CustomLookup, I am looking up the value Guid from my value cache and assigning it to CODE_VALUE.  This is because for those fields in Project 2007 that are based around an enterprise lookup table requires knowing and setting CODE_VALUE to the Guid that corresponds to the particular list value. 

More later.


Anonymous said...

How do create field maps?

Colby Africa said...

The field maps are not part of PSI, but rather an implementation detail specific to my tool. The concepts are pretty straightforward though. What is your scenario?


Content on this site is provided "AS IS" with no warranties and confers no rights. Additionally, all content on this site is my own personal opinion and does not represent my employer's view in any way.