Fields for custom content type not showing up

Topics: Troubleshooting, Writing modules
Oct 14, 2014 at 5:30 PM
Edited Oct 14, 2014 at 5:31 PM
I've created a module that is lifted almost step-by-step from the 1-N portion of the address module but cannot get the fields to show when I try to create a new content item.

The application is a sports archive site where I would like to identify each team as having a "type", such as a high school, college, professional team, etc.

I get the database table created and the team type as a new content type, but when I go to enter a new team type I only get a save button with no ability to enter any text.

I had hoped to be able to upload the module, but there doesn't seem to be any method to do so, so all the code is below. I appreciate any help.


Models\TeamTypePartRecord.cs
using Orchard.ContentManagement.Records;

namespace ScoresArchive.Models
{
    public class TeamTypePartRecord : ContentPartRecord
    {
        public virtual string Type { get; set; }
    }
}
Models\TeamTypePart.cs
using Orchard.ContentManagement;

namespace ScoresArchive.Models
{
    public class TeamTypePart : ContentPart<TeamTypePartRecord>
    {
        public string Type
        {
            get { return Record.Type; }
            set { Record.Type = value; }
        }
    }
}
Handlers\TeamTypePartHandler.cs
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
using ScoresArchive.Models;

namespace ScoresArchive.Handlers
{
    public class TeamTypePartHandler : ContentHandler
    {
        public TeamTypePartHandler(IRepository<TeamTypePartRecord> repository)
        {
            Filters.Add(StorageFilter.For(repository));
        }
    }
}
Drivers\TeamTypePartDriver.cs
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using ScoresArchive.Models;
using ScoresArchive.Services;
using ScoresArchive.ViewModels;

namespace ScoresArchive.Drivers
{
    [UsedImplicitly]
    public class TeamTypePartDriver : ContentPartDriver<TeamTypePart>
    {
        private readonly ITeamTypeService _teamTypeService;

        private const string TemplateName = "Parts/TeamType";

        public TeamTypePartDriver(ITeamTypeService teamTypeService)
        {
            _teamTypeService = teamTypeService;
        }

        protected override string Prefix
        {
            get { return "TeamType"; }
        }

        protected override DriverResult Display(
            TeamTypePart part,
            string displayType,
            dynamic shapeHelper)
        {

            return ContentShape("Parts_TeamType",
                            () => shapeHelper.Parts_TeamType(
                                ContentPart: part,
                                Type: part.Type
                                )
                                );
        }

        protected override DriverResult Editor(
            TeamTypePart part,
            dynamic shapeHelper)
        {

            return ContentShape("Parts_TeamType_Edit",
                    () => shapeHelper.EditorTemplate(
                        TemplateName: TemplateName,
                        Model: BuildEditorViewModel(part),
                        Prefix: Prefix
                        )
                        );
        }

        protected override DriverResult Editor(
            TeamTypePart part,
            IUpdateModel updater,
            dynamic shapeHelper)
        {

            var model = new EditTeamTypeViewModel();
            updater.TryUpdateModel(model, Prefix, null, null);

            if (part.ContentItem.Id != 0)
            {
                _teamTypeService.UpdateTeamTypeForContentItem(
                    part.ContentItem, model);
            }

            return Editor(part, shapeHelper);
        }

        private EditTeamTypeViewModel BuildEditorViewModel(TeamTypePart part)
        {
            var avm = new EditTeamTypeViewModel
            {
                Type = part.Type
            };
            return avm;
        }
    }
}
ViewModels\EditTeamTypeViewModel.cs
using System.Collections.Generic;
using ScoresArchive.Models;

namespace ScoresArchive.ViewModels
{
    public class EditTeamTypeViewModel
    {
        public string Type { get; set; }
    }
}
Services\TeamTypeService.cs
using System.Collections.Generic;
using System.Linq;
using Orchard;
using Orchard.ContentManagement;
using Orchard.Data;
using ScoresArchive.Models;
using ScoresArchive.ViewModels;

namespace ScoresArchive.Services
{
    public interface ITeamTypeService : IDependency
    {
        void UpdateTeamTypeForContentItem(
            ContentItem item, EditTeamTypeViewModel model);
    }

    public class TeamTypeService : ITeamTypeService
    {
        public void UpdateTeamTypeForContentItem(
            ContentItem item,
            EditTeamTypeViewModel model)
        {

            var teamTypePart = item.As<TeamTypePart>();
            teamTypePart.Type = model.Type;
        }
    }
}
Views\EditorTemplates\Parts\TeamType.cshtml
@model ScoresArchive.ViewModels.EditTeamTypeViewModel
<fieldset>
    <legend>TeamType</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.Type, T("Team Type"))
    </div>
    <div class="editor-field">
        @Html.TextAreaFor(model => model.Type)
        @Html.ValidationMessageFor(model => model.Type)
    </div>
</fieldset>
Views\Parts\TeamType.cshtml
<div class="teamType">@Model.Type</div>
placement.info
<Placement>
    <Place Parts_TeamType_Edit="Content:10"/>
    <Place Parts_TeamType="Content:10"/>
</Placement>
Migrations.cs
using System;
using System.Collections.Generic;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
using Orchard.Data;
using Orchard.Data.Migration;
using ScoresArchive.Models;

namespace ScoresArchive
{
    public class ScoresArchiveDataMigration : DataMigrationImpl
    {
        public int Create()
        {
            SchemaBuilder.CreateTable("TeamType",
                table => table
                    .ContentPartRecord()
                    .Column<string>("Type", column => column.Unique())
                );

            ContentDefinitionManager.AlterTypeDefinition("TeamType",
                cfg => cfg
                    .WithPart("TeamType")
                    .WithPart("CommonPart",
                        p => p
                            .WithSetting("OwnerEditorSettings.ShowOwnerEditor", "false")
                            .WithSetting("DateEditorSettings.ShowDateEditor", "false")
                            )
                    .Creatable(true)
                );

            return 1;
        }
    }
}
Oct 14, 2014 at 11:48 PM
Edited Oct 14, 2014 at 11:49 PM
I found the problem,

In the Migrations.cs file I should have specified ContentDefinitionManager.AlterTypeDefinition("TeamTypePart" and WithPart("TeamTypePart").

But... sometimes progress is just moving on to the next error!

Now when I enter a new Team Type I get the following error:


_An exception of type 'NHibernate.Exceptions.GenericADOException' occurred in NHibernate.dll but was not handled in user code

Additional information: could not execute batch command.[SQL: SQL not available]

If there is a handler for this exception, the program may be safely continued.
_

If I hit continue, then this error comes up:

_An exception of type 'NHibernate.AssertionFailure' occurred in NHibernate.dll but was not handled in user code

Additional information: null id in Orchard.ContentManagement.Records.ContentTypeRecord entry (don't flush the Session after an exception occurs)

If there is a handler for this exception, the program may be safely continued.
_

If I hit continue again, I get this on the website (along with a sizable Stack Trace that I will spare everyone:

_Server Error in '/OrchardLocal' Application.

null id in Orchard.ContentManagement.Records.ContentTypeRecord entry (don't flush the Session after an exception occurs)

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: NHibernate.AssertionFailure: null id in Orchard.ContentManagement.Records.ContentTypeRecord entry (don't flush the Session after an exception occurs)

Source Error:


Line 46:
Line 47: public IEnumerable<string> GetFeaturesThatNeedUpdate() {
Line 48: var currentVersions = _dataMigrationRepository.Table.ToDictionary(r => r.DataMigrationClass);
Line 49:
Line 50: var outOfDateMigrations = dataMigrations.Where(dataMigration => {

Source File: c:\Users\M\SkyDrive\Documents\Websites\Orchard.Test\src\Orchard\Data\Migration\DataMigrationManager.cs Line: 48

Marked as answer by LorenMaxwell on 10/16/2014 at 5:26 AM
Oct 15, 2014 at 12:08 AM
OK, narrowed down that problem as well.

The table should have been named "TeamTypePartRecord".

For anyone interested, the correct code for the Migrations.cs file is:
using System;
using System.Collections.Generic;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
using Orchard.Data;
using Orchard.Data.Migration;
using ScoresArchive.Models;

namespace ScoresArchive
{
    public class ScoresArchiveDataMigration : DataMigrationImpl
    {
        public int Create()
        {
            SchemaBuilder.CreateTable("TeamTypePartRecord",
                table => table
                    .ContentPartRecord()
                    .Column<string>("Type", column => column.Unique())
                );

            ContentDefinitionManager.AlterTypeDefinition("TeamTypePart",
                cfg => cfg
                    .DisplayedAs("Team Type")
                    .WithPart("TeamTypePart")
                    .WithPart("CommonPart",
                        p => p
                            .WithSetting("OwnerEditorSettings.ShowOwnerEditor", "false")
                            .WithSetting("DateEditorSettings.ShowDateEditor", "false")
                            )
                    .Creatable(true)
                );

            return 1;
        }
    }
}
Marked as answer by LorenMaxwell on 10/16/2014 at 5:26 AM