Отношения Orchard 1-N (останавливает обновление элемента содержимого)

Контекст: http://docs.orchardproject.net/Documentation/Creating-1-n-and-nn-relations

Вот модель моей дорожки:

    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; }
    }

А вот мои Миграции для создания 3 таблиц (2 информационных записи и 1 часть записи):

    // 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)
    );

Элемент содержимого прикрепляет часть дорожки (которая формирует отношение 1-n), а запись дорожки имеет список записей сеанса.

Проблема начинается, когда вы добавляете треки. Добавляются первые добавленные треки. После первого обновления (добавление первых треков, сессий пока нет) я больше не могу ничего обновлять в Content Item. Я не получаю никаких ошибок или каких-либо исключений, когда просматриваю код (возможно, они слишком глубоко запрятаны в Orchard, поэтому ничего очевидного не выдается).

Когда я перехожу к БД напрямую и удаляю записи отслеживания, связанные с элементом содержимого, я могу снова все обновить.

Я проверил журналы и нашел это:

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 ]

Во-первых, я не знаю, почему я получаю сообщение «недопустимое имя столбца».

Во-вторых, я не понимаю эту строку: UPDATE Ignite_EventsAgenda_SessionInformationRecord SET TrackInformationRecord_id = null WHERE TrackInformationRecord_id = @p0

Откуда он взял название столбца TrackInformationRecord_id?

Любая помощь или совет будут высоко оценены.


person AnimaSola    schedule 14.08.2013    source источник


Ответы (3)


Да, следует называть его слешем, а типы могут быть с именем класса записи вместо int. Вы также должны установить Datetime как обнуляемый: Datetime?

person Adam    schedule 15.08.2013

Не могли бы вы попробовать это так (для простоты я опустил Session, но вы можете скопировать то же самое):

public class TrackPartRecord : ContentPartRecord
{
    public virtual IList<TrackInformationRecord> Tracks { get; set; }
}

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

    // Relations properties
    public virtual TrackPartRecord TrackPartRecord { get; set; }
}

И в миграции:

        SchemaBuilder.CreateTable("TrackPartRecord", t => t
            .ContentPartRecord()
            );

        SchemaBuilder.CreateTable("TrackInformationRecord", t => t
            .Column<int>("Id", column => column.PrimaryKey().NotNull())
            .Column<int>("TrackPartRecord_Id")
            .Column<string>("Title", c => c.WithLength(50).NotNull())
            .Column<string>("Description", c => c.NotNull())
            .Column<bool>("IsDeleted")
           );
person Huy Do    schedule 15.08.2013

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

... говорит, что у родителя TrackInformationRecord много дочерних Sessions. Я предполагаю, что Orchard использует автоматическое сопоставление Fluent NHibernate под прикрытием для создания сопоставлений NHibernate. Имя столбца FluentNH по умолчанию для отношения «один ко многим» — {classNameOfParent}_id. Отсюда TrackInformationRecord_id, а отсюда и ошибка - вы никогда не создавали столбец с таким именем.

Я не знаком с Orchard, поэтому не знаю, предоставляет ли он способ настроить это поведение. FluentNH предоставляет способ (https://github.com/jagregory/fluent-nhibernate/wiki/Auto-mapping#overrides), но я не знаю, предоставляет ли Orchard вам эту функциональность или нет. Если вы найдете место для переопределения сопоставления, должно работать что-то вроде этого:

public class TrackInformationRecordOverride
    : IAutoMappingOverride<TrackInformationRecord>
{
    public void Override(AutoMapping<TrackInformationRecord> mapping)
    {
        mapping.HasMany(x => x.Sessions)
            .KeyColumn("TrackId"); // ... assuming TrackId is the column you wanted.
    }
}
person Daniel Schilling    schedule 15.08.2013