我正在尝试为2个具有彼此集合的类生成正确的映射。
我目前有一个Zone和一个Vehicle类。 Zone类包含包含区域的车辆列表。 Vehicle类包含包含Vehicle的区域列表。如您所见,这两个列表彼此直接相关。但是,在尝试保存我的一个对象时,我的映射一直给我一个外键约束错误。
有人可以解释我做错了吗?
以下是Vehicle类的映射:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Devices.Device, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Device`">
<id name="PK" type="System.Int64, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="PK" />
<generator class="identity" />
</id>
<version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" />
<joined-subclass name="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<key>
<column name="Device_id" />
</key>
<component name="Zones" access="property">
<bag name="_list" cascade="save-update" access="field" table="VehicleZones">
<key>
<column name="Veh_id"/>
</key>
<many-to-many class="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</bag>
</component>
<property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
</property>
</joined-subclass>
</class>
</hibernate-mapping>
这是我对Zone类的映射:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Zone`">
<id name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="PK"/>
<generator class="identity" />
</id>
<version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" />
<property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
</property>
<component name="Vehicles" access="property">
<bag name="_list" cascade="save-update" access="field" table="VehicleZones" inverse="true">
<key>
<column name="Zone_id" not-null="false"/>
</key>
<many-to-many class="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</bag>
</component>
</class>
</hibernate-mapping>
我通过以下方式保存区域和车辆:
using (var session = _sessionFactory.OpenSession())
{
foreach (Zone zone in Program.data.Zones.list)
{
session.SaveOrUpdate(zone);
}
foreach (Vehicle veh in Program.data.Vehicles.list)
{
session.SaveOrUpdate(veh);
}
}
之后我将区域添加到车辆列表和车辆到区域列表,然后我尝试通过以下方式保存列表:
using (var session = _sessionFactory.OpenSession())
{
foreach (Zone zone in Program.data.Zones.list)
{
foreach (Vehicle veh in Program.data.Vehicles.list)
{
veh.Zones.Add(zone);
zone.Vehicles.Add(veh);
}
}
using (var tx = session.BeginTransaction())
{
foreach (Vehicle veh in Program.data.Vehicles.list)
{
session.Update(veh.Zones);
}
tx.Commit();
}
}
此时Commit调用将抛出外键约束异常。我做错了什么?
答案 0 :(得分:0)
好的,我终于弄清楚我做错了什么。我最终确定的映射版本是:
车辆:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Devices.Device, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Device`">
<id name="PK" type="System.Int64, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="PK" />
<generator class="identity" />
</id>
<version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" />
<joined-subclass name="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<key>
<column name="Device_id" />
</key>
<component name="Zones" access="property">
<bag name="_list" cascade="save-update" access="field" table="VehicleZones" inverse="true">
<key>
<column name="veh_id" not-null="true"/>
</key>
<many-to-many class="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</bag>
</component>
<property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
</property>
</joined-subclass>
</class>
</hibernate-mapping>
区域:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Zone`">
<id name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="PK"/>
<generator class="identity" />
</id>
<version name="LastModifiedOn" column="LastModifiedOn" type="timestamp" access="field.pascalcase-underscore" />
<property name="ID" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
</property>
<component name="Vehicles" access="property">
<bag name="_list" cascade="save-update" access="field" table="VehicleZones">
<key>
<column name="veh_id" not-null="true"/>
</key>
<many-to-many class="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</bag>
</component>
</class>
</hibernate-mapping>
他们的主要原因是我所有的问题都是在区域映射方面设置的inverse =“true”。
如果您注意到我从区域侧移除了此标志并将其放在车辆端。该标志通知Hibernate哪个类负责维护关系。我正在保存车辆,而不是导致处理外键错误的区域。
因为我实际上希望车辆负责保存这种关系,所以我需要在Vehicle侧将逆集设置为true。我还需要将级联标记为“保存更新”,以便车辆将更新级联到区域并将关系链接到区域。因此,保存单个车辆链接表格中的区域以及保存区域对象,有效地修复了我在保存过程中遇到的错误。
现在保存工作正常。虽然我会建议采用以下方式保存这些项目的方法:
foreach (Vehicle veh in Program.data.Vehicles.list)
{
using (ITransaction tx = session.BeginTransaction())
{
session.Save(veh);
// Commit transactions
tx.Commit();
}
}
如果两个列表中有大量类。
原因是您的事务将在您调用提交期间锁定数据库中的项目。一旦调用了commit,就会实际执行所有更新和排队的所有内容。因此,保存仅仅是在调用提交后将实际事务发送到要发布的数据库。提交本身是所有实际工作发生的地方,一旦被调用,实际项目就存储在数据库中。显然你不希望交易花费很长一段时间。
在我的情况下,我试图节省5000辆车和9600个区域。这最终将导致负责存储包含4800万行的两个列表的表,因此每个车辆创建单独的事务和提交调用的原因。使用这种方法可以防止这些物品在这4800万个插入物的整个持续时间内被锁定,并且效率更高。而是在保存每辆车之后调用提交,因此除了第一个保存的车辆之外(因为第一个保存必须保存所有区域,如果它们不存在),每个车辆只发出9600个命令交易。这明显好于4800万。
但是我想指出,这不是一个样本量小得多的主要问题。这只是每个人都要考虑的事情。
希望这有助于任何偶然发现这一点的人。