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