DataMigration Documentation?

Topics: Customizing Orchard, Writing modules
Dec 11, 2011 at 7:13 PM

I just finished my first module which allows people to use the picasa rss album feed to display a Gallery of their images using the api and flash player.  These guides were key!

http://docs.orchardproject.net/Documentation/Creating-a-module-with-a-simple-text-editor

http://docs.orchardproject.net/Documentation/Writing-a-content-part

However, they don't go into the next step which is where I plan to add other features besides height and width...perhaps background color or speed, autoplay etc. That will require additional items to be stored in the database so lets pretend that today I store this:

 

     public int Create() {
			// Creating table PicasaGalleryRecord
            //this was autogenerated by the command above
			SchemaBuilder.CreateTable("PicasaGalleryRecord", table => table
				.ContentPartRecord()
				.Column("Width", DbType.Int32)
                .Column("Height", DbType.Int32)
                .Column("FeedUrl", DbType.String)
                .Column("ParsedUrl", DbType.String)
			);

            //added to make sure it can be added to other content parts and types.
            ContentDefinitionManager.AlterPartDefinition(
               typeof(PicasaGalleryPart).Name, cfg => cfg.Attachable());

            return 1;
        }

 

I understand that the "1" is the version number and that is stored in the Orchard_Framework_DataMigrationRecord table.  I also understand that somehow Orchard is smart enough to do some comparison to this table when I enable  or otherwise "update" my module.  Finally, I see from viewing other modules that this is done using a simple and straight forward UpdateFromX where X is the version you are upgrading from.

 

   public int UpdateFrom1()
        {
            //New stuff here?
          //I know it's not directly related to orchard but 
          //I'm confused on how to add it.  Can someone help?
            return 2;
        }


 

Here is where I need some help....  Would my Create *always* be the latest set (as if it never existed) then would I add my new Column to the UpdateFrom1 method?

So lets pretend I have a new bool called "AutoPlay".  I thinking I would do this:

     public int Create() {
			// Creating table PicasaGalleryRecord
            //this was autogenerated by the command above
			SchemaBuilder.CreateTable("PicasaGalleryRecord", table => table
				.ContentPartRecord()
				.Column("Width", DbType.Int32)
                .Column("Height", DbType.Int32)
                .Column("FeedUrl", DbType.String)
                .Column("ParsedUrl", DbType.String)
                .Column("AutoPlay", DbType.Boolean)
			);

            //added to make sure it can be added to other content parts and types.
            ContentDefinitionManager.AlterPartDefinition(
               typeof(PicasaGalleryPart).Name, cfg => cfg.Attachable());

            return 1;
        }

   public int UpdateFrom1()
        {
           //knowing v1 is missing the AutoPlay somehow add that.
          //I know it's not directly related to orchard but 
          //I'm confused on how to add it.  Can someone help?
            return 2;
        }

Can someone fill in the UpdateFrom1 for me as an example and also confirm that Create should be updated to reflect the "from scratch"?

Dec 11, 2011 at 7:34 PM

In UpdateFromX() methods you'll perform the next steps to upgrade the data structure. So in your case use SchemaBuilder.AlterTable ... AddColumn(..) to add your new columns.

That's all you actually need to do. But ...

Each method returns a number which tells Orchard the next step to sequentially run. So after your Create method, 1 is returned. Orchard then looks for UpdateFrom1(), finds it, runs that. Then it gets a 2 ... well, there's no UpdateFrom2(), so it knows no more upgrades are required right now. It saves in the database that it's currently on number 2. (It probably doesn't need saying, but these version numbers have absolutely nothing to do with the module version you specify in Module.txt)

At some point in the future, you add an UpdateFrom2(), Orchard sees that and knows there's a new upgrade pending.

What you can do, and what you'll see in the core Orchard modules, is basically "collapse" every new update into your Create method so you have everything there, and return the highest version number straight from there - i.e. return 2 as well, so you have a Create method that creates the whole structure and nothing else runs, and you have an UpdateFrom1() method for existing users who still need just the small changes to migrate to version 2. It makes fairly little difference if you do this. It just means that when a new user installs your module the system can perform everything in one batch, instead of multiple steps: cleaner, less prone to error, and probably trivially faster. So you don't need to do that, personally I don't always bother. (I don't know if anyone from the team can point out a more significant reason for doing this; but that's been my guess)

Hope that makes sense, let me know if you need clarification :)

Dec 11, 2011 at 7:55 PM

Beautiful reply and well spoken.  Thank you.

Dec 11, 2011 at 7:55 PM

Beautiful reply and well spoken.  Thank you.