Nhibernate 此计数为n的SqlParameterCollection的索引n无效

Nhibernate 此计数为n的SqlParameterCollection的索引n无效,nhibernate,fluent-nhibernate,Nhibernate,Fluent Nhibernate,当我试图保存一个Meter对象时,NHibernate抛出一个异常:“Count=n的此SqlParameterCollection的索引n无效。”。问题在于CurrentReading属性。如果我评论一下这一点,一切都很好。如果我在数据库中手动设置CurrentReading,NHibernate查询也会很好 我是NHibernate的新手,非常感谢您的帮助 我有以下课程: public class Meter { public virtual Guid Id { get; set;

当我试图保存一个Meter对象时,NHibernate抛出一个异常:“Count=n的此SqlParameterCollection的索引n无效。”。问题在于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; }
}
公共类仪表
{
公共虚拟Guid Id{get;set;}
公共虚拟字符串名称{get;set;}
公共虚拟表读取CurrentReading{get;protected set;}
私人IList_读数;
公共虚拟只读集合读数
{
获取{返回新的只读集合(_读数);}
}
公共虚拟void AddMeterReading(MeterReading MeterReading)
{
_读数。添加(仪表读数);
如果(CurrentReading==null | | MeterReading.ReadingTimestamp>CurrentReading.ReadingTimestamp)
{
电流读数=仪表读数;
}
}
}
公共类仪表读数
{
公共虚拟Guid Id{get;set;}
公共虚拟十进制用法{get;set;}
公共虚拟日期时间读取时间戳{get;set;}
}
这个fluent 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();
    }
}
公共密封类MeterMap:ClassMap
{
公共计量地图()
{
Id(x=>x.Id);
参考(m=>m.CurrentReading)
.列(“CurrentMeterReadingId”)
.LazyLoad()
.Cascade.None()
.Nullable();
有许多(x=>x个读数)
.KeyColumn(“MeterId”)
.Access.CamelCaseField(前缀.下划线)
.LazyLoad()
.Inverse()
.Cascade.All();
}
}
公共密封类MeterReadingMap:ClassMap
{
公共计量表ADINGMAP()
{
Id(x=>x.Id);
映射(x=>x.ReadingTimestamp)
.Not.Nullable();
映射(x=>x.Usage)
.精度(18)
.比额表(8)
.Not.Nullable();
}
}

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

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

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

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

可能太晚了(2012年发布的问题),但可能对其他人有用,我也有类似的问题。我没有使用Fluent映射,但我使用的是hbm文件。 据我所见,你有一个仪表,它有一个读数表。您已将此列表属性标记为反向,这很好。 但我的理解是,至少对于hbm映射文件,您必须在子项上添加一个“parent”属性(在您的示例中读取)以指向父项(在您的示例中为Meter)

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

您还必须设置子对象的父属性:

newReading.Meter = theParentMeter;
在我自己的示例中,父类中有一个Add方法可以为我执行此操作(将collection属性设置为只读,以强制代码用户调用此Add方法,确保始终设置父类):

回到最初的问题,我从Nhibernate 2.2直接升级到NH3.3.3.4001,并开始出现错误“Count=n的此SqlParameterCollection的索引n无效”。我用NH源代码进行了调试,发现AbstractEntityPersister方法遍历属性并在sql命令@p0、@p1等上设置它们。。。然后添加Id作为最后一个参数。我正在使用hilo id生成,因此该id是预先知道的

最初,我在父端没有inverse=true。 Decreate正在尝试设置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,一旦纠正,我在Deterheate中得到了以下sql命令:

INSERT INTO [ConstraintValue] (ConstraintId, ParameterId, Value, Id) VALUES (@p0, @p1, @p2, @p3)
这一次,属性数组中只有3个属性(@p0、@p1和@p2),“OrderId”在这个阶段的任何地方都没有提到。这3个属性在Deterheate中的for循环中设置,然后在for循环之后,通过IdentifierType.NullSafeSet将@p3设置为对象的Id

总而言之,我得到这个异常并不是因为我映射了两次相同的列或属性,而是因为我有一个父/子关系,在父级上没有inverse=true。

newReading.Meter = theParentMeter;
public virtual void AddConstraintValue(ConstraintValue cValue)
    {
        cValue.Constraint = this;
        _values.Add(cValue);
    }
INSERT INTO [ConstraintValue] (ParameterId, Value, ConstraintId, OrderId, Id) VALUES (@p0, @p1, @p2, @p3, @p4)
INSERT INTO [ConstraintValue] (ConstraintId, ParameterId, Value, Id) VALUES (@p0, @p1, @p2, @p3)