Свободное владение NHibernate — IndexOutOfRange

Я прочитал все сообщения и знаю, что IndexOutOfRange обычно происходит, потому что на столбец ссылаются дважды. Но я не понимаю, как это происходит, основываясь на моих сопоставлениях. Если в конфигурации SHOW_SQL установлено значение true, я вижу вставку в таблицу Events, а затем IndexOutOfRangeException, которая ссылается на таблицу RadioButtonQuestions. Я не вижу SQL, который он пытается использовать, который генерирует исключение. Я попытался использовать AutoMapping и теперь переключился на полное ClassMap для этих двух классов, чтобы попытаться сузить проблему.

public class RadioButtonQuestion : Entity
{
    [Required]
    public virtual Event Event { get; protected internal set; }

    [Required]
    public virtual string GroupIntroText { get; set; }
}

public class Event : Entity
{
    [Required]
    public virtual string Title { get; set; }

    [Required]
    public virtual DateTime EventDate { get; set; }

    public virtual IList<RadioButtonQuestions> RadioButtonQuestions { get; protected internal set; }
}




public class RadioButtonQuestionMap : ClassMap<RadioButtonQuestion>
{
    public RadioButtonQuestionMap()
    {
        Table("RadioButtonQuestions");

        Id(x => x.Id).Column("RadioButtonQuestionId").GeneratedBy.Identity();

        Map(x => x.GroupIntroText);
        References(x => x.Event).Not.Nullable();
    }
}


public class EventMap : ClassMap<Event>
{
    public EventMap()
    {
        Id(x => x.Id).Column("EventId").GeneratedBy.Identity();
        Map(x => x.EventDate);
        Map(x => x.Title);
        HasMany(x => x.RadioButtonQuestions).AsList(x => x.Column("ListIndex")).KeyColumn("EventId").Not.Inverse().Cascade.AllDeleteOrphan().Not.KeyNullable();
    }
}

Сгенерированный SQL выглядит правильно:

create table Events (
    EventId INT IDENTITY NOT NULL,
   EventDate DATETIME not null,
   Title NVARCHAR(255) not null,
   primary key (EventId)
)

create table RadioButtonQuestions (
    RadioButtonQuestionId INT IDENTITY NOT NULL,
   GroupIntroText NVARCHAR(255) not null,
   EventId INT not null,
   ListIndex INT null,
   primary key (RadioButtonQuestionId)
)

Это использует NH 3.3.0.4000 и FNH 1.3.0.727. Когда я пытаюсь сохранить новое событие (с прикрепленным RadioButtonQuestion), я вижу

NHibernate: ВСТАВИТЬ В события (EventDate, Title) VALUES (@p0, @p1); @p0 = 21.05.2012 12:32:11 [Тип: DateTime (0)], @p1 = 'Мое тестовое событие' [Тип: строка (0)] NHibernate: выберите @@IDENTITY

Events.Tests.Events.Tasks.EventTasksTests.CanCreateEvent: NHibernate.PropertyValueException : Ошибка обезвоживания значения свойства для Events.Domain.RadioButtonQuestion._Events.Domain.Event.RadioButtonQuestionsIndexBackref ----> System.IndexOutOfRangeException : SqlCeParameter с ParameterIndex '3' не содержится в этой коллекции SqlCeParameterCollection.

Итак, если на столбец действительно ссылаются дважды, в чем проблема с моей конфигурацией FNH, которая вызывает такое поведение? Я пытаюсь установить двунаправленные отношения (у одного события есть много вопросов по радиокнопкам) с упорядочением (я буду поддерживать его, поскольку NH не будет в двунаправленных отношениях, насколько я читал). FWIW Я также попробовал это как однонаправленную связь, удалив Event из RadioButtonQuestion, и это все равно вызвало то же исключение.


person Carl Bussema    schedule 21.05.2012    source источник
comment
FWIW, я могу получить исключение, если я использую Inverse() вместо Not.Inverse(), но это кажется странным... родитель должен управлять этим, поэтому я бы хотел Not.Inverse(), подумал я.   -  person Carl Bussema    schedule 21.05.2012
comment
Первое предложение этого вопроса было ответом, в котором я нуждался, хорошо сформулированным, спасибо!   -  person MrBoJangles    schedule 14.05.2013


Ответы (3)


У вас есть двунаправленная ассоциация, поэтому одна сторона должна быть помечена как Inverse(), и это может быть только коллекция RadioButtonQuestions. Если вы хотите, чтобы коллекция была владельцем, вы должны удалить ссылку на событие в своем классе RadioButtonQuestion.

Кроме того, столбец EventId в таблице RadioButtonQuestions не может принимать значения NULL, что может вызвать проблемы, если сопоставление коллекции не является обратным. См. примечание в документации.

person rumpelstiefel    schedule 21.05.2012
comment
Раздражающий. Мне действительно нужны двунаправленные отношения... Думаю, я могу жить с Inverse(), если это правильная модель в данном случае, и перечитывая документы по двунаправленным, кажется, что это единственный вариант. Интересно, почему это так. Думаю, NH действительно не хочет, чтобы вы использовали bidir ... вы также теряете автоматическую индексацию списка. Что касается nullable, мои модульные тесты для создания и обновления проходят, но я буду следить за этим. - person Carl Bussema; 21.05.2012

Я использую сопоставление в коде (NH 3.3.1) и заметил, что добавление Update(false) и Insert(false) решает проблему:

ManyToOne(x => x.DictionaryEntity, map =>
{
    map.Column("Dictionary");
    map.Update(false);
    map.Insert(false);
    map.Cascade(Cascade.None);
    map.Fetch(FetchKind.Select);
    map.NotFound(NotFoundMode.Exception);
    map.Lazy(LazyRelation.Proxy);
});
person Greg    schedule 29.08.2012
comment
Чудесно. Это решило мою проблему. Я использовал FluentNHibernate, и мне нужно было использовать: .Not.Update().Not.Insert(), но, тем не менее, он решил эту проблему. Спасибо! - person Christopher Currens; 14.01.2014

Я только что провел утро, искореняя эту ошибку. Первоначально исключение IndexOutOfRangeException направило меня по неверному пути, но я нашел причину. Моя проблема касалась карты классов FluentNHibernate, которая использует несколько компонентов; проблема заключалась в том, что два свойства были непреднамеренно и неправильно сопоставлены с одним и тем же столбцом:

до:

// example is stripped for simplicity, note the column names
Component(mappedClass => mappedClass.MappedComponent1,
          map => 
          {
              map.Map(c => c.SomeProperty, "samecolumn");
          });

Component(mappedClass => mappedClass.MappedComponent2,
          map => 
          {
              map.Map(c => c.OtherProperty, "samecolumn");
          });

после:

Component(mappedClass => mappedClass.MappedComponent1,
          map => 
          {
              map.Map(c => c.SomeProperty, "firstcolumn");
          });

Component(mappedClass => mappedClass.MappedComponent2,
          map => 
          {
              map.Map(c => c.OtherProperty, "secondcolumn");
          });

Как это приводит к исключению IndexOutOfRangeException, для меня не очевидно; Я предполагаю, что есть массив сопоставленных (исходных) свойств и массив столбцов назначения, и в этом случае массив назначения слишком короток для количества элементов в массиве исходных свойств, потому что некоторые столбцы назначения идентичны .

Я думаю, но стоит написать запрос на вытягивание для FluentNHibernate, чтобы проверить это и выдать более явное исключение.

person increddibelly    schedule 16.10.2018