Home > Orchard CMS > Defaulting on Orchard CMS

Defaulting on Orchard CMS

When creating a new Orchard module, I needed to set the default value for an integer. The thing is, you can’t do it in your model class like you would normally do. Property getter/setters are just getting/setting the underlying record, and the constructor runs before the record object has been created. What now?

The intrepid code will most likely try the DefaultValueAttribute next, and end up with something like.

[DefaultValue(5)]
public int FavoriteNum
{
    get { return Record.FavoriteNum; }
    set { Record.FavoriteNum = value; }
}

And, regrettably, this doesn’t work.

Our intrepid coder now scours the documentation and discovers the .WithDefault() method buried in the migrations code:

        public int Create()
        {
            SchemaBuilder.CreateTable("MyPartRecord", table => table
                    .ContentPartRecord()
                    .Column("FavoriteNum", c => c.NotNull().WithDefault(5))
                );
        }

Euphoria runs high, as the database does indeed construct the proper default constraint. Woo hoo! Except that Orchard doesn’t pass null to this value, it always gets 0. The wave of euphoria comes crashing down on the rocky shores of reality. Sad trombones lament your misfortune.

Don’t worry, you still have options. If your model class inherits from a class derived from ContentPart<TPartRecord>, all you need to do is initialize your value in TPartRecord‘s constructor. For example, assume MyPart inherits from ContentPart:

public class MyPart : ContentPart<MyPartRecord> {
	public int FavoriteNum {
		get { return Record.FavoriteNum; }
		set { Record.FavoriteNum = value;}
	}
}

public class MyPartRecord : ContentPartRecord {
	public MyPartRecord() { FavoriteNum = 5; }
	public virtual int FavoriteNum { get; set; }
}

But what if your model class inherits from ContentPart instead? The ContentPartclass lives in the Orchard framework, and so we aren’t able to use the above technique. If you’ve been down this road, then you know it feels like a dead-end. We’re in luck, though. Our solution comes via the event hooks that are exposed by deriving a class from ContentHandler. In particular, we need to pass your default-value-setting code to the OnInitializing method. Here is an example part handler class that finally does what we’ve been trying to do:

using System;
using System.Collections.Generic;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;
using Contrib.MyModule.Models;

namespace Contrib.MyModule.Handlers
{
    public class MyPartHandler : ContentHandler
    {
        public MyPartHandler(IRepository repository)
        {
            Filters.Add(StorageFilter.For(repository));
            OnInitializing((context, part) => {
                part.FavoriteNum = 32;
              });
        }
    }
}

And there was much rejoicing. Happy coding!

Advertisements
  1. 04/04/2011 at 12:39 PM

    What about initializing from the record constructor?

    • Zack
      04/04/2011 at 1:30 PM

      It threw a NullReferenceException. That’s when I switched gears and tried the OnInitialization technique which worked like a charm.

      • 04/04/2011 at 1:52 PM

        uh? What did? I mean, what was null?

      • 04/04/2011 at 1:53 PM

        I mean, the Record constructor, not the part constructor…

      • Zack
        04/04/2011 at 2:34 PM

        The Record object was null when initializing from the Part. Embarrassingly, I never tried MyPartRecord’s constructor. To be honest, I don’t understand the ContentPartRecord lifecycle as well as I’d like to. I do like keeping my initialization code all in the same spot, and so I never looked beyond the OnInitializing method. Went back and confirmed it works.

        I appreciate the tip. I’ll update the article accordingly.

    • Zack
      04/04/2011 at 2:43 PM

      I don’t always provide a record class for my model classes (much like BlogPostPart). In fact, I try not to whenever possible.

      • 04/04/2011 at 6:15 PM

        It’s a little weird that you would try not to. BlogPostPart is a little special as it is like a marker interface, contentless. I do understand there are cases where you can’t have a record, and this trick is indeed useful for those. Thanks for the precisions.

      • Zack
        04/04/2011 at 8:03 PM

        Once I learned the .As trick, I’ve been amazed how far the built-in common.models will get me. That in turn let’s me leverage lots of other built-in functionality like the ItemController, the default route, parts, etc. Of course, sometimes I have no choice but to create a new table, content record class, etc., but much of the work I’ve done so far hasn’t required it all that often.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: