Storing non-content data in Orchard

Dry earthA CMS like Orchard is, by definition, designed to store content. What differentiates content from other kinds of data is rather subtle. The way I would describe it is by saying that if you would put each instance of a kind of data on its own web page, if it would make sense to add comments to it, or tags, or ratings, then it is content and you can store it in Orchard using all the convenient composition options that it offers. Otherwise, it probably isn't and you can store it using somewhat simpler means that I will now describe.

In one of the modules I wrote, Vandelay.ThemePicker, there is some configuration data for the module. That data is not content by the definition I gave above. Let's look at how this data is stored and queried.

The configuration data in question is a set of records, each of which has a number of properties:

public class SettingsRecord {
    public virtual int Id { get; set;}
    public virtual string RuleType { get; set; }
    public virtual string Name { get; set; }
    public virtual string Criterion { get; set; }
    public virtual string Theme { get; set; }
    public virtual int Priority { get; set; }
    public virtual string Zone { get; set; }
    public virtual string Position { get; set; }
}

Each property has to be virtual for nHibernate to handle it (it creates derived classed that are instrumented in all kinds of ways). We also have an Id property.

The way these records will be stored in the database is described from a migration:

public int Create() {
    SchemaBuilder.CreateTable("SettingsRecord",
        table => table
            .Column<int>("Id", column => column.PrimaryKey().Identity())
            .Column<string>("RuleType", column => column.NotNull().WithDefault(""))
            .Column<string>("Name", column => column.NotNull().WithDefault(""))
            .Column<string>("Criterion", column => column.NotNull().WithDefault(""))
            .Column<string>("Theme", column => column.NotNull().WithDefault(""))
            .Column<int>("Priority", column => column.NotNull().WithDefault(10))
            .Column<string>("Zone", column => column.NotNull().WithDefault(""))
            .Column<string>("Position", column => column.NotNull().WithDefault(""))
        );
    return 1;
}

When we enable the feature, the migration will run, which will create the table in the database.

Once we've done that, all we have to do in order to use the data is inject an IRepository<SettingsRecord>, which is what I'm doing from the set of helpers I put under the SettingsService class:

private readonly IRepository<SettingsRecord> _repository;
private readonly ISignals _signals;
private readonly ICacheManager _cacheManager;

public SettingsService(
    IRepository<SettingsRecord> repository,
    ISignals signals,
    ICacheManager cacheManager) {
    _repository = repository;
    _signals = signals;
    _cacheManager = cacheManager;
}

The repository has a Table property, which implements IQueryable<SettingsRecord> (enabling all kind of Linq queries) as well as methods such as Delete and Create.

Here's for example how I'm getting all the records in the table:

_repository.Table.ToList()

And here's how I'm deleting a record:

_repository.Delete(_repository.Get(r => r.Id == id));

And here's how I'm creating one:

_repository.Create(new SettingsRecord {
    Name = name,
    RuleType = ruleType,
    Criterion = criterion,
    Theme = theme,
    Priority = priority,
    Zone = zone,
    Position = position
});

In summary, you create a record class, a migration, and you're in business and can just manipulate the data through the repository that the framework is exposing. You even get ambient transactions from the work context.

4 Comments

  • Nice one! This should definitely land in the Orchard docs.

  • I agree with Piotr Szmyd that this should go into Orchard docs

  • It's a wiki...

  • I'm trying this exact thing and I can't get it to work for some reason. The migration creates the table correctly, the repository is injected just fine into the service, but even though there is a record in the table, _repository.Table contains no records. I ran a SQL server trace but I can't find the query being that should be run on the database.

    A few points to note - I want to retrieve this data in a command, and the data that I want to retrieve are pre-populated (not created by Orchard).

    Is there any reason the repository would not be hitting the database? I assume all the ORM mappings are handled internally by Orchard.

    Sorry if it's something obvious - I'm a bit new to Orchard.

    Thanks for your help.

Comments have been disabled for this content.