Неверный индекс n для этой SqlParameterCollection с Count = n - PullRequest
3 голосов
/ 15 февраля 2012

NHibernate генерирует исключение: «Неверный индекс n для этой коллекции SqlParameterCollection с Count = n».когда я пытаюсь сохранить объект Meter.Проблема со свойством CurrentReading.Если я прокомментирую это планирование, все хорошо.Также, если я вручную установлю CurrentReading в базу данных, NHibernate запрашивает его нормально.

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

У меня есть следующие классы:

public class Meter
{
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }

    public virtual MeterReading CurrentReading { get; protected set; }

    private IList<MeterReading> _readings;
    public virtual ReadOnlyCollection<MeterReading> Readings
    {
        get { return new ReadOnlyCollection<MeterReading>(_readings); }
    }

    public virtual void AddMeterReading(MeterReading MeterReading)
    {
        _readings.Add(MeterReading);
        if (CurrentReading == null || MeterReading.ReadingTimestamp > CurrentReading.ReadingTimestamp)
        {
            CurrentReading = MeterReading;
        }
    }
}

public class MeterReading
{
    public virtual Guid Id { get; set; }
    public virtual decimal Usage { get; set; }
    public virtual DateTime ReadingTimestamp { get; set; }
}

И этот свободный файл отображения nhibernate:

public sealed class MeterMap : ClassMap<Meter>
{
    public MeterMap()
    {
        Id(x => x.Id);

        References(m => m.CurrentReading)
            .Column("CurrentMeterReadingId")
            .LazyLoad()
            .Cascade.None()
            .Nullable();

        HasMany(x => x.Readings)
            .KeyColumn("MeterId")
            .Access.CamelCaseField(Prefix.Underscore)
            .LazyLoad()
            .Inverse()
            .Cascade.All();
    }
}

public sealed class MeterReadingMap : ClassMap<MeterReading>
{
    public MeterReadingMap()
    {
        Id(x => x.Id);

        Map(x => x.ReadingTimestamp)
            .Not.Nullable();

        Map(x => x.Usage)
            .Precision(18)
            .Scale(8)
            .Not.Nullable();
    }
}

Ответы [ 3 ]

3 голосов
/ 15 февраля 2012

Я полагаю, что это связано с двойным отображением одного и того же столбца.Вот что обычно означает эта ошибка.Вы можете попробовать это альтернативное сопоставление, так как вы не используете каскадирование в CurrentMeterReading:

References(m => m.CurrentReading)
        .Column("CurrentMeterReadingId")
        .Not.Update()
        .Not.Insert();
        .Nullable();

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

2 голосов
/ 23 июля 2013

У меня была такая же проблема.Моя ошибка была;У меня было свойство ассоциации (многие-к-одному), и в моем отображении не было указано insert="false" для этой ассоциации.

0 голосов
/ 19 сентября 2013

Возможно, слишком поздно (вопрос опубликован в 2012 году), но может быть полезным для других, у меня была похожая проблема. Я не использую отображение Fluent, но я использую файлы hbm. Из того, что я вижу, у вас есть метр, который имеет список показаний. Вы пометили это свойство List как Inverse, что хорошо. Но, насколько я понимаю, по крайней мере с файлами отображения hbm, вы должны добавить свойство parent к дочернему элементу (чтение в вашем примере), чтобы указывать на родителя (Meter в вашем примере).

Это мой родительский объект (называется Constraint):

    <list name="Values" access="field.camelcase-underscore" table="[ConstraintValue]" cascade="all-delete-orphan" inverse="true">
        <key column="ConstraintId" not-null="true"/>
        <list-index column="OrderId" />
        <one-to-many class="ConstraintValue" />
    </list>

А это мой дочерний объект (называется Constraint Value):

    <!--Parent-->
    <many-to-one name="Constraint" access="field.camelcase-underscore" class="Constraint" column="ConstraintId" cascade="merge" not-null="true"/>

И также важно помнить, что в коде нельзя просто добавить дочерний элемент к родителю:

Meter.Readings.Add(newReading);

Вы также должны установить родительское свойство потомка:

newReading.Meter = theParentMeter;

В моем собственном примере у меня есть метод Add в родительском классе, чтобы сделать это для меня (установите свойство коллекции как доступное только для чтения, чтобы заставить пользователей кода вызывать этот метод Add, гарантируя, что родитель всегда набор):

public virtual void AddConstraintValue(ConstraintValue cValue)
    {
        cValue.Constraint = this;
        _values.Add(cValue);
    }

Возвращаясь к первоначальному вопросу, я обновил Nhibernate 2.2 напрямую до NH 3.3.3.4001 и начал получать сообщение об ошибке «Неверный индекс n для этой коллекции SqlParameterCollection с Count = n». Я отладил исходный код NH и обнаружил, что метод Dehydrate AbstractEntityPersister просматривает свойства и устанавливает их для команды sql @ p0, @ p1 и т. Д., А затем добавляет Id в качестве последнего параметра. Я использую Hilo ID Generation, поэтому ID известен заранее.

Изначально у меня не было inverse = true на родительской стороне. Дегидрат пытался установить команду sql:

INSERT INTO [ConstraintValue] (ParameterId, Value, ConstraintId, OrderId, Id) VALUES (@p0, @p1, @p2, @p3, @p4)

но каким-то образом @ p0 и @ p3 были установлены на один и тот же hilo Id, я ожидал, что @ p3 будет «порядком» списка (число типа 0, 1 или 2), а затем он попытается установить фактический идентификатор объекта, как индекс = 5, и я получаю исключение.

Затем я наконец-то понял, что пропустил inverse = true , и после исправления получил команду sql в Dehydrate:

INSERT INTO [ConstraintValue] (ConstraintId, ParameterId, Value, Id) VALUES (@p0, @p1, @p2, @p3)

И на этот раз в массиве свойств было только 3 свойства (@ p0, @ p1 и @ p2), «OrderId» даже нигде не упоминается на данном этапе. Эти 3 свойства задаются в цикле for в Dehydrate, а затем после этого для идентификатора @ p3 устанавливается идентификатор объекта с помощью IdentifierType.NullSafeSet сразу после цикла for.

Подводя итог, я получил это исключение не потому, что дважды сопоставил один и тот же столбец или свойство, а потому, что у меня были родительские / дочерние отношения без обратного = true для родителя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...