Overview of Extensibility for Database Refactoring

You can extend the capabilities of database refactoring to provide new types of refactoring or to refactor new file types. You can implement both types of extensibility for database refactoring by creating feature extensions. Before you create feature extensions for database refactoring, you should understand how the components of database refactoring interact and where you can extend those components.

To enable database refactoring to operate on new targets, you can create custom refactoring contributors by inheriting from the RefactoringContributor abstract base class. For example, you can support refactoring into text files or XML files that are contained in the database project.

To enable new refactoring types that are not included with Visual Studio Premium or Visual Studio Ultimate, you can create custom refactoring operations by inheriting from the RefactoringOperation  abstract base class. For example, you might implement a new refactoring type to replace nested conditionals with guard clauses in a series of separate IF statements.

Database Refactoring and Refactoring Contributors

The following diagram illustrates how database refactoring uses components known as refactoring contributors to handle specific types of refactoring.

Extensibility Overview for Database Refactoring

Extensibility Overview for Database Refactoring

When you apply a database refactoring operation for the first time in your current session of Visual Studio, the refactoring feature is loaded together with all refactoring types and contributors. The command that you specified is passed to the refactoring feature and the specified refactoring type is started. The refactoring contributor manager loops through each contributor that is registered for the specified refactoring type. Each type of contributor applies to a different object or set of objects, and each type can have a different data flow.

When you implement a new type of refactoring, you must create the contributors that are required to support that type of refactoring operation. For example, you might want to create a new refactoring type that replaces nested conditionals with guard clauses. Since that type of refactoring would only change the bodies of procedures or functions, and would not change the names of any database objects, you would only have to create a schema object contributor and a script contributor.

Schema Object Contributors

The following diagram shows the data flow for a refactoring contributor that handles database schema objects.

Data Flow for a Schema Object Contributor

Data Flow for the Schema Object Contributor

A schema object contributor updates the definition of a schema object. The contributor updates the Copy On Write Store in the Data Schema Model. The updated model element is passed to the Script Domain Object Model (Script DOM) Builder and is used to generate an updated Script DOM. The updated Script DOM is compared with the Script DOM of the original definition of that object by the Script DOM Diff Engine, and an updated script is generated.

Reference Contributors

The following diagram shows the data flow for a reference contributor that handles references between objects.

Data Flow for a Reference Contributor

Data Flow for the Reference Contributor

A reference contributor retrieves all references and their offsets from the Data Schema Model and updates the references in the Copy On Write Store of the Data Schema Model. The updated Script DOM is compared with the original Script DOM, and the results are used to update the scripts that contain the references that were changed.

Data Generation Plans and Database Unit Test Contributors

The following diagram shows the data flow for data generation plans and database unit test contributors.

Data Flow for Data Generation Plans and Database Unit Test Contributors

Data Flow for DGen and UnitTest Contributors

A contributor for data generation plans uses XPathNavigator to find and update changes in the data generation plan, which is an XML file.

A contributor for database unit tests analyzes the .resx file for the database unit test, and extracts the script strings that are stored in that file. Those script strings are then processed using the same data flow as a database script contributor.

Database Script Contributors

The following diagram shows the data flow for a database script contributor.

Data Flow for a Database Script Contributor

Data Flow for the Database Script Contributor

A database script contributor handles updates for pre-deployment scripts and post-deployment scripts, for other .sql scripts, and for the SQL script strings extracted from database unit tests. The Model Builder takes the script and builds a model of it in the temporary store of the Data Schema Model. The temporary store is used to create a modified Script DOM model. That modified model is compared with the model from the original script, and the differences are used to generate the final updated script.

Custom Contributors

You can create your own custom contributors to support additional refactoring targets that were not described earlier in this topic. For example, you can create a custom contributor to update text files, database documentation, or output from third-party tools. You must determine the correct data flow that is required to support the refactoring target. You should reference the types described earlier in this topic if the new target type resembles the target types of an existing contributor.

Database Refactoring Types

You can enable new types of refactoring by creating a new refactoring type. You create new refactoring types by implementing at least four classes that inherit from the following base classes:

  • RefactoringCommand
    You register this class to provide a new type of refactoring. The class specifies for which model elements the command should be available, and it calls your refactoring operation when the user clicks the command.

  • RefactoringOperation
    This class specifies how your refactoring operation interacts with the preview window, specifies properties that describe the operation, and creates the ContributorInput.

  • ContributorInput
    This class stores the input data to the RefactoringContributor. If your primary contributor needs secondary contributors to complete the refactoring operation, you might have to create multiple classes derived from ContributorInput. For example, if you are changing the name of an object, you not only have to modify the object itself, but you must also modify all references to that object. Therefore, you would create one ContributorInput for the symbol, and another for all references to the symbol.

  • RefactoringContributor
    This class builds a list of change proposals, based on the specified input. As with the ContributorInput, you might have to create multiple classes derived from RefactoringContributor. If you need a secondary ContributorInput, your primary RefactoringContributor creates that input. You must declare the database schema providers with which your refactoring contributors are compatible. You must also register all contributors for a refactoring type and the refactoring command.

Database Refactoring Targets

You can extend a registered type of refactoring to operate on a new target, such as a new type of model element or a new file. To enable refactoring to operate on a new target, you must create new refactoring contributors. The new contributor must be able to operate on one of the defined ContributorInputs for that refactoring type. You create a new refactoring target or contributor by implementing at least one class that inherits from the following base class:

  • RefactoringContributor
    This class builds a list of change proposals, based on the specified input. You must declare the database schema providers with which your refactoring contributors are compatible, and you must register all contributors for a refactoring type.