Just forget that Repository<T> exists, please.

If there’s a class that’s caused Orchard users more confusion, bugs, and disappointment than Repository<T>, I’d like to know about it… Generic repositories are a well-known anti-pattern, something that the designers of the Orchard data layer were fully aware of, but decided to use anyway as helpers in the implementation of this piece of code that bridges Orchard’s runtime dynamic type system to nHibernate’s database mappings. The class should arguably have been made internal or private (which is something you won’t hear me say every day), but it wasn’t, and now we’re stuck with it until we get to redesign that part of the platform.

So generic repositories are not a good idea in general, but in Orchard, they are even worse, because their scope is on the part record, whereas the atom of data is the content item. A content item may be a composite of parts, but it rarely if ever makes sense to query or modify a part outside of the context of its content item.

This is why Repository<T> is entirely the wrong data API to use in all but exceptional circumstances. Instead, one should use one of the APIs that are available on ContentManager, such as Query, HqlQuery, or even directly the nHibernate Session object. If you use Repository<T>, you are running the great risk of destroying the consistency of your content items, creating orphan parts, and you won’t see higher-level concepts such as versioning and published state.

Yet, it seems to be irresistible to lots of users, because its CRUD API looks familiar, and because its IQueryable<T> Table property is just too tempting… Mmmmm, Linq!

In summary, apologies for the existence of Repository<T>, but if you could forget it, you would do yourself a huge favor.

2 Comments

  • So what should we use for non-content tables? Modules such as the Contrib.Voting use the IRepository<> extensively.

  • That's why I said "in all but exceptional circumstances". Non-content tables are such a case, but even there, I would use the nHibernate session object directly: Repository<T> doesn't really offer anything that you can't have from the session, so that's one more level of abstraction that you don't need.

Comments have been disabled for this content.