Dear Core Team,
There are some complexities with managing EF migrations in a multi-developer environment. In fact, you really have to avoid having a situation where multiple developers have created overlapping (or parallel) migrations. We've found it's best to use the following high-level strategy for adding migrations to source control:
- Pull latest develop branch and make sure you've run the latest migrations
- If needed, merge your develop into your feature branch.
- Claim the Migration Token (core team internal use only)
- Create a new migration for your branch and test, test, test (up and down).
- If needed, merge your feature branch to the develop branch.
- Push your develop branch to origin.
You should wait util your code is ready to commit to the develop branch before you build a migration. Once your migration is pushed it's essentially going to include it into everyone else's development environment/database. You better get it right ;) ...but if you don't, see the section below on how to undo the trouble you might have created.
Review and use the following checklists.
High Level Steps When Making Model Changes
- Add to the Model and compile
- Claim the Migration Token (core team internal use only)
- Add-Migration AddExampleNewPropertyToSomeModel (for example)
- Update-Database
- Run the Rock.CodeGeneration tool
- Commit/push if stable or finish next step if needed before commit/push.
- Then whatever UI blocks, etc need to be updated to take advantage of the new change or feature
Create the new migration class
- Run any dev tools such as
Dev Tools\Sql\CodeGen_PagesBlocksAttributesMigration.sql
script. It will output stuff you'll want to use in your next step.
- Run
Add-Migration [YOUR_MIGRATION_NAME]
- Edit this skeleton migration and paste in the stuff from the MigrationUp output into your migration's
Up()
method and then the MigrationDown output into the Down()
method. Pay particular attention to the order that things are deleted since you cannot delete many things unless any related items are first deleted.
- REVIEW each item you just pasted. Not all of them will be things you should include in your migration.
- Manually add any other data items that were not already accounted for by the SQL script including:
- EntityTypes
- NoteTypes
- PageContext (if any of your blocks use Context you should double-check this one)
- Global Attributes
Verify Your Assumptions
You MUST double check your SQL looking for possible problems with your assumptions. Use the following checklist to help you verify your SQL:
- Include GOOD comments. Tell us what you're doing!
- Never use an ID always use a GUID. If you need an ID go fetch it using a GUID.
- SELECT TOP(1) instead of assuming there is only one
- Explicitly add any needed attributes for your new block types. DON'T rely on the system to add them for you.
Important: You should consider a few things when you're creating your Up()
and Down()
migration. For example, if your migration adds a new NoteType
be aware that there could be Note
records using it. Those notes are things you did not create and it might be problematic if you destroyed that data. Similarly, if you could not delete it during a Down()
then you probably should check if it exists already during the Up()
. Therefore you may want to do something like this in the Up()
:
public override void Up()
{
Sql( @"
-- Add 'Prayer Comment' NoteType if it's not already there
DECLARE @PrayerCommentNoteTypeId int
SELECT @PrayerCommentNoteTypeId = [Id] FROM [NoteType] WHERE [Guid] = '0EBABD75-0890-4756-A9EE-62626282BB5D'
IF @PrayerCommentNoteTypeId IS NULL
BEGIN
INSERT INTO [NoteType] ...
...
");
// ...
}
... and this in the Down()
:
public override void Down()
{
Sql( @"
-- Delete the NoteType but ONLY if it's not being used...
IF NOT EXISTS(SELECT * FROM [Note] WHERE [NoteTypeId] IN
(SELECT [Id] FROM [NoteType] WHERE [Guid] = '0EBABD75-0890-4756-A9EE-62626282BB5D' )
)
BEGIN
DELETE [NoteType] WHERE [Guid] = '0EBABD75-0890-4756-A9EE-62626282BB5D'
END
");
// ...
}
Note: You can use the methods listed in the Migration Helper Methods section below.
###Regarding quotes in migrations
Be sure to double-up any quotations that you make within a SQL command. For example, if you were tp want to have a string that said {He said "Rock"}, then you would write it as 'He said ""Rock""'. If working with JSON values within a SQL command, remember to only use double single-quotation marks, as the double double-quotation marks are used to distinguish between JSON keys and values.
Test your new migration class
- Replace your db name with a new database name into your RockContext connection string in your
web.connectionStrings.config
file.
- Run Update-Database to see if it worked.
- Verify everything by running Rock (F5) and checking every detail of your stuff.
- If it's not good, return to step 3 in the previous section; otherwise proceed to next step.
- Test your
Down()
migration by migrating back to the last migration that exists before your new migration. Use the Update-Database -TargetMigration:[THE_PREVIOUS_ONE]
. If that was successful, continue.
- If applicable, add some data using your new blocks (if any) and re-test your
Down()
and your Up()
migrations. This could shake out a few more assumptions you've made about your migration.
- When everything is looking A-OK, proceed to the Commit/Push/Deploy section; otherwise go back to step 3 in the previous section.
NOTE: Never delete your migration before you run a 'Down' migration (targetting the previous migration).
Commit/Push/Deploy
If everything looks good, you can commit your changes, merge into the develop branch (as needed), and push up to origin develop branch.
Trouble During Pull and Rebase
If you run into trouble during a git pull rebase it probably implies that someone else committed a migration before yours. You should consider the following steps to undo/reorder your migration to come after the other new migrations.
- Determine if you should ignore (exclude from project) any new migrations that might be in your Rock.csproj file. Resolve conflicts enough to be able to load the Rock project in Visual Studio.
- Perform an
Update-Database -TargetMigration:[THE_PREVIOUS_ONE]
to return to the migration prior to yours.
- Make a copy of you migration file (outside of your solution) and delete it.
- Re-include any migrations (if you excluded them in step 1) and run Update-Database.
- Recreate your migration using the procedure described in the earlier section.
- When everything's ready commit and push your changes to Github.
Migration Helper Methods
ActionTypeAttributeValue
Method |
Description |
Signature |
AddActionTypeAttributeValue |
Adds the action type attribute value. |
string actionTypeGuid , string attributeGuid , string value |
ActionTypePersonAttributeValue
Method |
Description |
Signature |
AddActionTypePersonAttributeValue |
Adds an action type person attribute value. Because there's not way to link to another person in target database, person attribute values are just set to the first person alias record in target database which will most likely be the Admin, Admin record. |
string actionTypeGuid , string attributeGuid , string value |
Attribute
Method |
Description |
Signature |
DeleteAttribute |
Deletes the attribute. |
string guid |
AttributeQualifier
Method |
Description |
Signature |
AddAttributeQualifier |
Adds the attribute qualifier. |
string attributeGuid , string key , string value , string guid |
AttributeValue
Method |
Description |
Signature |
AddAttributeValue |
Adds a new attribute value for the given attributeGuid if it does not already exist. |
string attributeGuid , int entityId , string value , string guid |
BinaryFileType
Method |
Description |
Signature |
UpdateBinaryFileType |
Updates the type of the binary file. |
string storageEntityTypeId , string name , string description , string iconCssClass , string guid , bool allowCaching , bool requiresViewSecurity |
Block
Method |
Description |
Signature |
AddBlock |
Adds a new Block of the given block type to the given page (optional) and layout (optional), setting its values with the given parameter values. If only the layout is given, edit/configuration authorization will also be inserted into the Auth table for the admin role (GroupId 2). |
string pageGuid , string layoutGuid , string blockTypeGuid , string name , string zone , string preHtml , string postHtml , int order , string guid |
DeleteBlock |
Deletes the block and any authorization records that belonged to it. |
string guid |
BlockAttribute
Method |
Description |
Signature |
DeleteBlockAttribute |
Deletes the block Attribute. |
string guid |
BlockAttributeValue
Method |
Description |
Signature |
AddBlockAttributeValue |
Adds a new block attribute value for the given block guid and attribute guid, deleting any previously existing attribute value first. |
string blockGuid , string attributeGuid , string value , bool appendToExisting |
DeleteBlockAttributeValue |
Deletes the block attribute value. |
string blockGuid , string attributeGuid |
BlockType
Method |
Description |
Signature |
AddBlockType |
Adds a new BlockType. |
string name , string description , string path , string category , string guid |
UpdateBlockType |
Updates the BlockType by path (if it exists); otherwise it inserts a new record. In either case it will be marked IsSystem. |
string name , string description , string path , string category , string guid |
DeleteBlockType |
Deletes the BlockType. |
string guid |
BlockTypeAttribute
Method |
Description |
Signature |
AddBlockTypeAttribute |
Adds a new BlockType Attribute for the given blocktype and key. |
string blockTypeGuid , string fieldTypeGuid , string name , string key , string category , string description , int order , string defaultValue , string guid , bool isRequired |
UpdateBlockTypeAttribute |
Updates the BlockType Attribute for the given blocktype and key (if it exists); otherwise it inserts a new record. |
string blockTypeGuid , string fieldTypeGuid , string name , string key , string category , string description , int order , string defaultValue , string guid |
Category
Method |
Description |
Signature |
UpdateCategory |
Updates the category. |
string entityTypeGuid , string name , string iconCssClass , string description , string guid , int order |
DeleteCategory |
Deletes the category. |
string guid |
DefinedType
Method |
Description |
Signature |
AddDefinedType |
Adds a new DefinedType. |
string category , string name , string description , string guid , string helpText |
DeleteDefinedType |
Deletes the DefinedType. |
string guid |
DefinedTypeAttribute
Method |
Description |
Signature |
AddDefinedTypeAttribute |
Adds the defined type attribute. |
string definedTypeGuid , string fieldTypeGuid , string name , string key , string description , int order , string defaultValue , string guid |
DefinedValue
Method |
Description |
Signature |
AddDefinedValue |
Adds a new DefinedValue for the given DefinedType. |
string definedTypeGuid , string value , string description , string guid , bool isSystem |
UpdateDefinedValue |
Updates (or Adds) the defined value for the given DefinedType. |
string definedTypeGuid , string value , string description , string guid , bool isSystem |
DeleteDefinedValue |
Deletes the DefinedValue. |
string guid |
DefinedValueAttributeValue
Method |
Description |
Signature |
AddDefinedValueAttributeValue |
Adds the defined value attribute value. |
string definedValueGuid , string attributeGuid , string value |
UpdateDefinedValueAttributeValue |
Adds the defined value attribute value. |
string definedValueGuid , string attributeGuid , string value |
DefinedValueAttributeValueByValue
Method |
Description |
Signature |
AddDefinedValueAttributeValueByValue |
Adds the name of the defined value attribute value by. |
string definedTypeGuid , string definedValueValue , string attributeKey , string value |
DefinedValueByValue
Method |
Description |
Signature |
UpdateDefinedValueByValue |
Updates the name of the defined value by. |
string definedTypeGuid , string value , string description , int order , bool isSystem |
EntityAttribute
Method |
Description |
Signature |
AddEntityAttribute |
Adds a new EntityType Attribute for the given EntityType, FieldType, and name (key). |
string entityTypeName , string fieldTypeGuid , string entityTypeQualifierColumn , string entityTypeQualifierValue , string name , string category , string description , int order , string defaultValue , string guid |
UpdateEntityAttribute |
Updates the Entity Attribute for the given EntityType, FieldType, and name (key). otherwise it inserts a new record. |
string entityTypeName , string fieldTypeGuid , string entityTypeQualifierColumn , string entityTypeQualifierValue , string name , string description , int order , string defaultValue , string guid |
EntityType
Method |
Description |
Signature |
UpdateEntityType |
Updates the EntityType by name (if it exists); otherwise it inserts a new record. |
string name , string guid , bool isEntity , bool isSecured |
UpdateEntityType |
Updates the EntityType by name (if it exists); otherwise it inserts a new record. |
string name , string friendlyName , string assemblyName , bool isEntity , bool isSecured , string guid |
DeleteEntityType |
Deletes the EntityType. |
string guid |
EntityTypeMultiValueFieldType
Method |
Description |
Signature |
UpdateEntityTypeMultiValueFieldType |
Updates the EntityType MultiValueFieldType |
string entityTypeName , string fieldTypeGuid |
EntityTypeSingleValueFieldType
Method |
Description |
Signature |
UpdateEntityTypeSingleValueFieldType |
Updates the EntityType SingleValueFieldType |
string entityTypeName , string fieldTypeGuid |
FieldType
Method |
Description |
Signature |
UpdateFieldType |
Updates the FieldType by assembly and className (if it exists); otherwise it inserts a new record. |
string name , string description , string assembly , string className , string guid , bool IsSystem |
DeleteFieldType |
Deletes the FieldType. |
string guid |
GlobalAttribute
Method |
Description |
Signature |
AddGlobalAttribute |
Adds a global Attribute for the given FieldType, entityTypeQualifierColumn, entityTypeQualifierValue and name (key). Note: This method delets the Attribute first if it had already existed. |
string fieldTypeGuid , string entityTypeQualifierColumn , string entityTypeQualifierValue , string name , string description , int order , string defaultValue , string guid |
Group
Method |
Description |
Signature |
DeleteGroup |
Deletes the group. |
string guid , bool orphanAnyChildren |
GroupMemberAttributeDefinedValue
Method |
Description |
Signature |
AddGroupMemberAttributeDefinedValue |
Adds or updates a group member Attribute for the given group for storing a particular defined value. The defined values are constrained by the given defined type. |
string groupGuid , string name , string description , int order , string defaultValue , bool isGridColumn , bool isMultiValue , bool isRequired , string definedTypeGuid , string guid , bool isSystem |
UpdateGroupMemberAttributeDefinedValue |
Adds or updates a group member Attribute for the given group for storing a particular defined value. The defined values are constrained by the given defined type. |
string groupGuid , string name , string description , int order , string defaultValue , bool isGridColumn , bool isMultiValue , bool isRequired , string definedTypeGuid , string guid , bool isSystem |
GroupType
Method |
Description |
Signature |
DeleteGroupType |
Deletes the GroupType. |
string guid |
GroupTypeGroupAttribute
Method |
Description |
Signature |
AddGroupTypeGroupAttribute |
Adds a new GroupType "Group Attribute" for the given GroupType using the given values. |
string groupTypeGuid , string fieldTypeGuid , string name , string description , int order , string defaultValue , string guid |
GroupTypeRole
Method |
Description |
Signature |
AddGroupTypeRole |
Adds or Updates the GroupTypeRole for the given guid (if it exists); otherwise it inserts a new record. Can also set the role as the default for the given GroupType if isDefaultGroupTypeRole is set to true. |
string groupTypeGuid , string name , string description , int order , int? maxCount , int? minCount , string guid , bool isSystem , bool isLeader , bool isDefaultGroupTypeRole |
UpdateGroupTypeRole |
Adds or Updates the GroupTypeRole for the given guid (if it exists); otherwise it inserts a new record. Can also set the role as the default for the given GroupType if isDefaultGroupTypeRole is set to true. |
string groupTypeGuid , string name , string description , int order , int? maxCount , int? minCount , string guid , bool isSystem , bool isLeader , bool isDefaultGroupTypeRole |
DeleteGroupTypeRole |
Deletes the GroupTypeRole. |
string guid |
HtmlContentBlock
Method |
Description |
Signature |
UpdateHtmlContentBlock |
Add or Updates the HTML content for an HTML Content Block |
string blockGuid , string htmlContent , string guid |
Layout
Method |
Description |
Signature |
AddLayout |
Adds a new Layout to the given site. |
string siteGuid , string fileName , string name , string description , string guid |
DeleteLayout |
Deletes the Layout. |
string guid |
Page
Method |
Description |
Signature |
AddPage |
Adds a new Page to the given parent page. The new page will be ordered as last child of the parent page. |
string parentPageGuid , string layoutGuid , string name , string description , string guid , string iconCssClass , string insertAfterPageGuid |
MovePage |
Moves the Page to the new given parent page. |
string pageGuid , string parentPageGuid |
DeletePage |
Deletes the Page and any PageViews that use the page. |
string guid |
PageContext
Method |
Description |
Signature |
AddPageContext |
|
string pageGuid , string entity , string idParameter |
UpdatePageContext |
Adds or Updates PageContext to the given page, entity, idParameter |
string pageGuid , string entity , string idParameter , string guid |
DeletePageContext |
Deletes the page context. |
string guid |
PageRoute
Method |
Description |
Signature |
AddPageRoute |
Adds a new PageRoute to the given page but only if the given route name does not exist. |
string pageGuid , string route |
PersonAttribute
Method |
Description |
Signature |
UpdatePersonAttribute |
Updates the BlockType Attribute for the given blocktype and key (if it exists); otherwise it inserts a new record. |
string fieldTypeGuid , string categoryGuid , string name , string key , string iconCssClass , string description , int order , string defaultValue , string guid |
PersonAttributeCategory
Method |
Description |
Signature |
UpdatePersonAttributeCategory |
Updates the person attribute category. |
string name , string iconCssClass , string description , string guid , int order |
PersonBadge
Method |
Description |
Signature |
UpdatePersonBadge |
Updates the PersonBadge by Guid (if it exists); otherwise it inserts a new record. |
string name , string description , string entityTypeName , int order , string guid |
PersonBadgeAttribute
Method |
Description |
Signature |
AddPersonBadgeAttribute |
Adds (or Deletes and Adds) the person badge attribute. |
string personBadgeGuid , string fieldTypeGuid , string name , string key , string description , int order , string defaultValue , string guid |
PersonBadgeAttributeValue
Method |
Description |
Signature |
AddPersonBadgeAttributeValue |
Adds/Updates the person badge attribute value. |
string personBadgeGuid , string attributeGuid , string value |
Report
Method |
Description |
Signature |
AddReport |
Adds a report. |
string categoryGuid , string dataViewGuid , string entityTypeGuid , string name , string description , string guid , int? fetchTop |
DeleteReport |
Deletes the report |
string guid |
ReportField
Method |
Description |
Signature |
DeleteReportField |
Deletes the report field. |
string guid |
SecurityAuth
Method |
Description |
Signature |
AddSecurityAuth |
Adds the security auth record for the given entity type and group. |
string entityTypeName , string action , string groupGuid , string authGuid |
DeleteSecurityAuth |
Deletes the security auth record. |
string guid |
SecurityAuthForAttribute
Method |
Description |
Signature |
AddSecurityAuthForAttribute |
Adds the attribute security authentication. Set GroupGuid to null when setting to a special role |
string attributeGuid , int order , string action , bool allow , string groupGuid , int specialRole , string authGuid |
DeleteSecurityAuthForAttribute |
Deletes the security authentication for page. |
string attributeGuid |
SecurityAuthForBinaryFileType
Method |
Description |
Signature |
AddSecurityAuthForBinaryFileType |
Adds the binaryfiletype security authentication. Set GroupGuid to null when setting to a special role |
string binaryFileTypeGuid , int order , string action , bool allow , string groupGuid , Rock.Model.SpecialRole specialRole , string authGuid |
SecurityAuthForBlock
Method |
Description |
Signature |
AddSecurityAuthForBlock |
Adds the page security authentication. Set GroupGuid to null when setting to a special role |
string blockGuid , int order , string action , bool allow , string groupGuid , Rock.Model.SpecialRole specialRole , string authGuid |
DeleteSecurityAuthForBlock |
Deletes the security authentication for block. |
string blockGuid |
SecurityAuthForCategory
Method |
Description |
Signature |
AddSecurityAuthForCategory |
Adds the category security authentication. Set GroupGuid to null when setting to a special role |
string categoryGuid , int order , string action , bool allow , string groupGuid , int specialRole , string authGuid |
DeleteSecurityAuthForCategory |
Deletes the security authentication for category. |
string categoryGuid |
SecurityAuthForEntityType
Method |
Description |
Signature |
AddSecurityAuthForEntityType |
Adds the security auth record for the given entity type and group. |
string entityTypeName , int order , string action , bool allow , string groupGuid , int specialRole , string authGuid |
SecurityAuthForGroupType
Method |
Description |
Signature |
AddSecurityAuthForGroupType |
Adds the page security authentication. Set GroupGuid to null when setting to a special role |
string groupTypeGuid , int order , string action , bool allow , string groupGuid , Rock.Model.SpecialRole specialRole , string authGuid |
DeleteSecurityAuthForGroupType |
Deletes the security authentication for groupType. |
string groupTypeGuid |
SecurityAuthForPage
Method |
Description |
Signature |
AddSecurityAuthForPage |
Adds the page security authentication. Set GroupGuid to null when setting to a special role |
string pageGuid , int order , string action , bool allow , string groupGuid , int specialRole , string authGuid |
DeleteSecurityAuthForPage |
Deletes the security authentication for page. |
string pageGuid |
SecurityRoleGroup
Method |
Description |
Signature |
AddSecurityRoleGroup |
Adds the security role group. |
string name , string description , string guid |
DeleteSecurityRoleGroup |
Deletes the security role group. |
string guid |
Site
Method |
Description |
Signature |
AddSite |
Adds a new Layout to the given site. |
string name , string description , string theme , string guid |
DeleteSite |
Deletes the Layout. |
string guid |
SystemEmail
Method |
Description |
Signature |
DeleteSystemEmail |
Deletes the SystemEmail. |
string guid |
WorkflowActionEntityAttribute
Method |
Description |
Signature |
UpdateWorkflowActionEntityAttribute |
Updates the workflow action entity attribute. |
string actionEntityTypeGuid , string fieldTypeGuid , string name , string key , string description , int order , string defaultValue , string guid |
WorkflowActivityTypeAttribute
Method |
Description |
Signature |
UpdateWorkflowActivityTypeAttribute |
Updates the workflow activity type attribute. |
string workflowActivityTypeGuid , string fieldTypeGuid , string name , string key , string description , int order , string defaultValue , string guid |
WorkflowTypeAttribute
Method |
Description |
Signature |
UpdateWorkflowTypeAttribute |
Updates the workflow type attribute. |
string workflowTypeGuid , string fieldTypeGuid , string name , string key , string description , int order , string defaultValue , string guid |