How can I create a ContentItem from C# code?

Topics: Customizing Orchard, General, Writing modules
May 3, 2016 at 6:34 AM
I'm trying to implement a mechanism to transfer old data from old DB to Orchard CMS. I've already build the ContentType via Orchard dashboard, then manage to build AdminController to do it, but creating it via code confuse me. Please help me and point me in the right direction.
May 3, 2016 at 7:22 PM
You can create new content items of a particular content typy using the IContentManager service. If you look for its usages you will see how it works. For example, the Contents module in the Orchard.Core project uses it to allow the user to create and manage content items.
May 3, 2016 at 8:03 PM
Thanks for the reply. My content item is named "Announcement" and it has parts:
  • CommonPart
  • AutoroutePart
  • TitlePart
  • BodyPart
  • IdentityPart
and 2 fields:
  • Media library picker field named 'ExtraInfoFile'
  • Date time field named 'ReleaseDate'
I use this method to create it:
public void CreateAnnouncement(IDictionary<string, object> oldContent) {
    var theUser = AuthSvc.GetAuthenticatedUser();
    var idCul = CultureMgr.GetCultureByName("id-ID");
    var enCul = CultureMgr.GetCultureByName("en-US");

    if (oldContent["Title"] != null) {
        var anc = OrchardSvc.ContentManager.New("Announcement");

        anc.As<CommonPart>().Owner = theUser;
        anc.As<AutoroutePart>().DisplayAlias = "announcement/" + oldContent["Name"] + "-old-id";
        anc.As<TitlePart>().Title = oldContent["Title"].ToString();
        anc.As<BodyPart>().Format = "";
        anc.As<BodyPart>().Text = (oldContent["Text"] != null ? oldContent["Text"].ToString() : "");
        anc.As<IdentityPart>().Identifier = "old-data-" + oldContent["Id"].ToString();
        anc.As<LocalizationPart>().Culture = idCul;
        var fields = (anc as dynamic).Announcement.Fields as IEnumerable<ContentField>;
        var releaseDateField = fields.First(f => f.Name == "ReleaseDate");
        var ExtraInfoFileField = fields.First(f => f.Name == "ExtraInfoFile"); // how to correctly fill this from known filepath still eludes me
        (releaseDateField as dynamic).DateTime = (DateTime)oldContent["CreatedDate"];

        OrchardSvc.ContentManager.Create(anc, VersionOptions.Published);
The oldContent dictionary object contains the old db. As seen above, the ExtraInfoFile field is still untouched as I still don't know how to properly deal with it.

The big problem with the above is, that when I run it, the method returns fine but Orchard suddenly throws SQL query timeout exception in content manager's get available versions method. Subsequent refresh of the website doesn't show any new Announcement and occasionally throws the previously stated SQL timeout exception. Restarting Orchard makes everything runs OK again (no SQL timeout) but the supposedly created Announcement is still non-existent.

Please help me. Please. I'm confused.
May 3, 2016 at 8:42 PM
Look at the Orchard.MediaLibrary module to see what properties are exposed by the MediaLibraryPickerField class. Be aware that the media library picker field points to media content items (which are content items stereotyped as "Media"). This means that you cannot simply set a path. Unless of course you already imported the images as content items, then you just need to just map the old path to the new media content item, which you can then set on the media library picker field.

By the way, there's an easier way to access content fields on parts.
For example:
dynamic dynAnnouncement = anc;
var releaseDateField = dynAnnouncement.Announcement.ReleaseDate;
Regarding the SQL timeout, it doesn't look like it is related to the code you pasted in. Are you connecting to the old database in the same transaction that may be causing this issue? Perhaps this thread has some hints?
May 3, 2016 at 9:03 PM
I'll check it out. Thanks.