1-N relationships (stops Content Item from updating)

Topics: Customizing Orchard, Troubleshooting, Writing modules
Aug 14, 2013 at 1:44 PM
Context: http://docs.orchardproject.net/Documentation/Creating-1-n-and-n-n-relations

Here is the model of my Track Part:
    public class TrackPartRecord : ContentPartRecord
    {
        public virtual IList<TrackInformationRecord> Tracks { get; set; }
    }

    public class TrackPart : ContentPart<TrackPartRecord>
    {
        public IList<TrackInformationRecord> Tracks
        {
            get { return Record.Tracks; }
        }
    }

    public class TrackInformationRecord
    {
        public virtual int Id { get; set; }
        public virtual int TrackPartId { get; set; }
        public virtual string Title { get; set; }
        public virtual string Description { get; set; }
        public virtual bool IsDeleted { get; set; }

        public virtual IList<SessionInformationRecord> Sessions { get; set; }
   }

    public class SessionInformationRecord
    {
        public virtual int Id { get; set; }
        public virtual int TrackId { get; set; }
        public virtual string Title { get; set; }
        public virtual string Description { get; set; }
        public virtual DateTime Timeslot { get; set; }
        public virtual bool HasEvaluation { get; set; }
        public virtual bool IsDeleted { get; set; }
    }
And here is my migrations to create the 3 tables (2 information records, and 1 part record):
            // Creating table TrackInformationRecord
            SchemaBuilder.CreateTable("TrackInformationRecord", table => table
                .Column("Id", DbType.Int32, column => column.PrimaryKey().Identity())
                .Column("TrackPartId", DbType.Int32)
                .Column("Title", DbType.String)
                .Column("Description", DbType.String)
                .Column("IsDeleted", DbType.Boolean)
            );

            // Creating table TrackPartRecord
            SchemaBuilder.CreateTable("TrackPartRecord", table => table
                .ContentPartRecord()
            );

            ContentDefinitionManager.AlterPartDefinition("TrackPart", builder => builder.Attachable());

            // Creating table SessionInformationRecord
            SchemaBuilder.CreateTable("SessionInformationRecord", table => table
                .Column("Id", DbType.Int32, column => column.PrimaryKey().Identity())
                .Column("TrackId", DbType.Int32)
                .Column("Title", DbType.String)
                .Column("Description", DbType.String)
                .Column("Timeslot", DbType.DateTime)
                .Column("HasEvaluation", DbType.Boolean)
                .Column("IsDeleted", DbType.Boolean)
            );
A Content Item attaches the Track Part (which forms the 1-n relationship) and the Track record has a list of Session records.

The problem begins when you add Tracks. The first tracks added are added. After the first update (adding the first tracks, no sessions yet), I am no longer able to update anything on the Content Item. I don't get any errors or any exceptions when I go through the code (maybe they are buried too deep in Orchard that nothing directly apparent is thrown).

When I go to the db directly and delete the Track records related to the Content Item, I am able to update everything once again.

I checked the logs and found this:
2013-08-14 14:15:00,882 [30] NHibernate.AdoNet.AbstractBatcher - Could not execute command: UPDATE Ignite_EventsAgenda_SessionInformationRecord SET TrackInformationRecord_id = null WHERE TrackInformationRecord_id = @p0
System.Data.SqlServerCe.SqlCeException (0x80004005): The column name is not valid. [ Node name (if any) = ,Column name = TrackInformationRecord_id ]
   at System.Data.SqlServerCe.SqlCeCommand.ProcessResults(Int32 hr)
   at System.Data.SqlServerCe.SqlCeCommand.CompileQueryPlan()
   at System.Data.SqlServerCe.SqlCeCommand.ExecuteCommand(CommandBehavior behavior, String method, ResultSetOptions options)
   at System.Data.SqlServerCe.SqlCeCommand.ExecuteNonQuery()
   at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd)
2013-08-14 14:15:00,888 [30] NHibernate.Util.ADOExceptionReporter - System.Data.SqlServerCe.SqlCeException (0x80004005): The column name is not valid. [ Node name (if any) = ,Column name = TrackInformationRecord_id ]
   at System.Data.SqlServerCe.SqlCeCommand.ProcessResults(Int32 hr)
   at System.Data.SqlServerCe.SqlCeCommand.CompileQueryPlan()
   at System.Data.SqlServerCe.SqlCeCommand.ExecuteCommand(CommandBehavior behavior, String method, ResultSetOptions options)
   at System.Data.SqlServerCe.SqlCeCommand.ExecuteNonQuery()
   at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd)
   at NHibernate.Persister.Collection.AbstractCollectionPersister.Remove(Object id, ISessionImplementor session)
2013-08-14 14:15:00,891 [30] NHibernate.Util.ADOExceptionReporter - The column name is not valid. [ Node name (if any) = ,Column name = TrackInformationRecord_id ]
2013-08-14 14:15:00,894 [30] NHibernate.Event.Default.AbstractFlushingEventListener - Could not synchronize database state with session
NHibernate.Exceptions.GenericADOException: could not delete collection: [Ignite.EventsAgenda.Models.TrackInformationRecord.Sessions#1][SQL: UPDATE Ignite_EventsAgenda_SessionInformationRecord SET TrackInformationRecord_id = null WHERE TrackInformationRecord_id = @p0] ---> System.Data.SqlServerCe.SqlCeException: The column name is not valid. [ Node name (if any) = ,Column name = TrackInformationRecord_id ]
Firstly, I don't know why I'm getting the "column name is not valid" issue.

Second, I don't get this line: UPDATE Ignite_EventsAgenda_SessionInformationRecord SET TrackInformationRecord_id = null WHERE TrackInformationRecord_id = @p0

Where did it get the column name TrackInformationRecord_id?
Developer
Aug 14, 2013 at 1:49 PM
Im not sure but I think you need to add

public virtual TrackInformationRecord TrackInformation { get; set; }

to the SessionInformationRecord record. Then in SessionInformationRecord migration add

public virtual int TrackInformation_Id { get; set; }
Aug 14, 2013 at 2:03 PM
Thanks for your quick reply Jetski.

I already have the TrackId in the Session record. Do you mean I should do away with that and have the TrackInformation entity in place instead?
    public class SessionInformationRecord
    {
        public virtual TrackInformationRecord TrackInformation { get; set; }  <--- Add

        public virtual int Id { get; set; }
        //public virtual int TrackId { get; set; } <--- Remove
        public virtual string Title { get; set; }
        public virtual string Description { get; set; }
        public virtual DateTime Timeslot { get; set; }
        public virtual bool HasEvaluation { get; set; }
        public virtual bool IsDeleted { get; set; }
    }