具有Count = n的此SqlParameterCollection的索引n无效

时间:2012-02-14 23:11:26

标签: nhibernate fluent-nhibernate

NHibernate抛出异常:“此SqlParameterCollection的索引n无效,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 个答案:

答案 0 :(得分:3)

我的猜测是它与两次映射同一列有关。这就是这个错误通常意味着什么。您可以尝试使用此替代映射,因为您没有在CurrentMeterReading上使用级联:

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

另外我认为默认情况下启用了延迟加载,所以我认为不需要在映射中指定它。

答案 1 :(得分:2)

我遇到了同样的问题。我的错误是;我有一个关联属性(多对一),并且在我的映射中没有为该关联指定insert="false"

答案 2 :(得分:0)

也许为时已晚(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>

这是我的子对象(称为约束值):

    <!--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方法为我做(将collection属性设置为只读以强制代码的用户调用此Add方法,确保父代总是集):

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

回到最初的问题,我从Nhibernate 2.2直接升级到NH 3.3.3.4001并开始得到错误“此SqlParameterCollection的无效索引n,其中Count = n”。我使用NH源代码调试,发现AbstractEntityPersister Dehydrate方法遍历属性并在sql命令@ p0,@ p1等上设置它们然后将Id添加为最后一个参数。我正在使用hilo id生成,所以id是事先知道的。

最初,我在父方没有 inverse = true 。 Dehydrate试图设置sql命令:

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

但不知何故@ p0和@ p3被设置为相同的hilo Id,我被期望@ p3成为列表的“顺序”(0,1或2之类的数字)然后它会尝试设置对象的实际ID,索引= 5,我得到异常。

然后,我终于意识到我错过了 inverse = true ,一旦纠正,我在Dehydrate中得到了这个sql命令:

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

这一次,属性数组中只有3个属性(@ p0,@ p1和@ p2),在这个阶段甚至没有提到“OrderId”。这三个属性在Dehydrate中的for循环中设置,然后在for循环之后,通过IdentifierType.NullSafeSet将@ p3设置为对象的Id。

总结一下,我得到这个例外的原因不是因为我两次映射了相同的列或属性,而是因为我在父级上没有使用inverse = true的父/子关系。