Create Content Part with a ContentPartRecord and Table vs in a MIgration file with only ContentPartDefinition

Topics: Customizing Orchard
Feb 23, 2015 at 1:31 PM
If this needs to be split into multiple questions please let me know

I'm new to orchard and trying to get my head around the difference between:
  1. Creating a content part with a Content Part Record, driver, handler, and table as in
  2. Creating the part in a migration file using ContentPartDefinition and defining the fields there, as in In this case the view for the content part could be overriden with an Alternate that targets the type. I'm using creating a part as an example but a content type could be created this way as well.
I searched the forums and have read:

From what I gather a custom content part (or content type) should be created in code with a DB backing if the fields need to be queryable. But what does that mean exactly?

I'm using Orchard 1.8.1 and just created a Content Type Definition using the Admin UI. I am able to create a query using those fields for filtering and sorting using the "Queries" page in the Admin UI. Is this ability something new?

I guess the bottom line is: if a custom content type doesn't need any logic, except maybe some view logic, does it need to be created like the MapPart example with ContentPartRecord, driver, handler, DataTable, etc? It seems that MapPart could just as well have been created in a Migration file using the ContentPartDefinition syntax, or even in the Admin UI.

My company is deciding on what CMS to use for our next intranet so any response will not only be helpful but will give me an indicator of how active the community is.

Feb 23, 2015 at 2:28 PM
Edited Feb 23, 2015 at 2:29 PM
This post might help clarifying (starting from the section Anatomy of a Content Item):

In a nutshell:
  • A (custom) content part is a thing that can be attached to a content type and is represented as a database entity.
  • Content parts have a collection of content fields, which themselves are also represented as database entities.
  • A content part can be codified by creating a C# class that has the same name as the content part and derives from the ContentPart class. This enables you to store data as part of the content part through strongly typed properties instead of (or in addition to) content fields.
  • To add behavior to a codified content part, you implement a content part driver for this content part class (this is also a requirement for the content part to be automatically welded onto the content item, which means that when accessing the part on a content item, that part instance will be an actual C# instance of the part class, not just of type ContentPart, allowing you to access its properties.)
  • When implementing properties on a content part class, you need a backing mechanism. This can either be a) InfoSet or b) a database record. With 1.8, you should choose InfoSet storage by default (no need for a record class representing the part), unless you want to be able to use the content manager API to query for content items by content part properties. In that case, your part needs to inherit from ContentPart<TRecord>, where TRecord is a POCO mapped to a database table. This is discussed in the documentation.
Hope this helps.
Feb 23, 2015 at 3:53 PM
Edited Feb 23, 2015 at 4:33 PM
Thanks Sipke for your quick reply. I've read a lot of your Orchard posts on your blog, including the one you referenced. That post is amazing. Rereading it now that I have some more Orchard knowledge helps. The bullet points help a lot too. Previously I didn't know there was a distinction between Content Part properties vs adding Content Fields to Content Parts. I now see that you can attach fields to a part using AlterPartDefinition (or the Admin UI) but properties have to be declared in a class that derives from type ContentPart. Content Part properties cannot be created in the Admin UI.

I do have some follow up questions:
  1. I can use the "Queries" page in the Admin UI to filter and sort on fields of a content type that I created in the Admin UI. I understand that when I create a new type definition Orchard actually creates a Content Part of the same name behind the scenes and the fields get attached to the part. So does this mean that fields of a content part are queryable by the content manager API as well? I assume the "Queries" page uses that behind the scenes, but I can't find it in the source code to verify.
  2. Just to make sure I understand your last bullet point: The MapPart example would still work if MapPart inherited from ContentPart, as opposed to ContentPart<MapPartRecord>. The properties in the MapPart class would look the same because Store and Retrieve use InfoSet document storage and will only sync with Record storage if a custom Record class is defined on the Part. Also, there would be no need for the CreateTable call in the Migration file because there is no database backing for those properties.
  3. I was a little surprised when I found out I need to manually create database Table definitions for any custom part or field. I would think that defining the properties on the ContentPart would automatically take care of database storage and that's the point of an ORM - it can infer the types and do the low-level database stuff for you. I have a little experience with Entity Framework and none with NHibernate so that may be my problem.
Thanks again for your contribution to this project!
Feb 23, 2015 at 4:19 PM
Exactly. Happy to hear.
  1. No, you can't use the content manager API to query for content by content fields. However, the way the Projections module does this is by maintaining a separate index table that stores all the field values by content item, then queries (or joins with) that table. Bertrand wrote an article about this very topic.
  2. Aced it.
  3. I don't know why it is the way it is. Perhaps the reason was to have more control over table creation in terms of column types and length. One could use attributes of course, but I think you would still have to write migration steps if your model changes (e.g. add a new property/column). Will EF automatically generate these migrations?
Feb 23, 2015 at 4:42 PM
Great. I finally feel like I can start now. Getting passed these concepts was make-it-or-break-it for me and you've helped me make it.

Regarding migrations - you know I forgot that the Migration.cs file can be automatically generated in Orchard using codegen datamigration. I thought I had to create the Migration file manually. Brain must be overloaded. It's the same way in EF.

And lastly sorry for spelling your name wrong (now corrected :) )
Feb 23, 2015 at 5:00 PM
Happy to help.