You don't need a "controller", you need a "service."
A Controller controls the flow of the application based on user input and other events that occur in lower layers. A Service just naively goes about its business doing what it was told.
The migration service object would have the intelligence for pulling data from the old schema and persisting it to the new schema via a web service if necessary, or an entirely different API. This service should have the minimum amount of dependencies to get the job done:
- Domain model classes for each database
- Data access classes for each database
- Methods or other classes that map one domain model to another
The PropertyMigrationService
has the following responsibilities
- Knowing where to pull data from
- Knowing where to save data to
- Having access to the mapping objects to map one domain model to another
It would need:
OldDataAccess
- A class for CRUD operations on the old DB
Property
- The domain model for the "property" in the old DB
Subdivision
- Domain model for subdivisions in the old DB
Owner
- Domain model for owners in the old DB
NewDataAccess
- A class for CRUD operations on the new DB/web service
Address
- Domain model for properties in the new DB
Owner
- Domain model for owners in the new DB
PropertyToAddressMapper
- Mapping Property
objects in the old DB to Address
objects for the new DB
SubdivisionToAddressMapper
- Mapping Subdivision
objects in the old DB to Address
objects for the new DB
OwnerToOwnerMapper
- Map owner objects from one DB to another
You'll end up with this object hierarchy:
PropertyMigrationService
OldDataAccess
NewDataAccess
PropertyToAddressMapper
SubdivisionToAddressMapper
OwnerToOwnerMapper
The migration service could have a single public method called void migrate()
that performs the migration.
Having dealt with legacy schemas, you never know what manner of madness and chaos you'll encounter. Architecting the solution in this manner, in conjunction with having your data access classes implement an interface, and have the PropertyMigrationService
use those objects through their interface, you can make this whole migration process unit-testable.
Now you can throw a bunch of tests at this for known error conditions and really make this thing bullet proof (well, bullet resistant).
After this is wrapped in a service object, you have some flexibility for when and where this gets invoked:
- From a "controller" in a web application
- From a script kicked off as a cron job in Linux or scheduled task in Windows
The migration process becomes both proactive (user clicks a button on the web page and does the migration) or passive (a schedule task executes at midnight and does these records in batches of, say, 1,000).