NHibernate.StaleStateException : Unexpected row count: 0; expected: 1
Hl Guys,
I am busy writing a backend administrative program for a system that exists. I have selected NHibernate for my data access solution and am fairly new to it. I am experiencing the following error in a parent/child relationship:
NHiber开发者_如何学编程nate.StaleStateException : Unexpected row count: 0; expected: 1
This error is caused by the fact that in my source code I add the new child object into the parent’s children collection of MeetingAdministrators. When I save the parent object I expect the children to be added as well, however an INSERT is generated only for the parent object. Nhibernate does not generate an INSERT for the child but instead attempts to UPDATE the child even though it does not exist. Thus it brings up the error message shown above. I have looked everywhere on the web and nhibernate documentation for this scenario but have not found any help. Most code involves foreign keys that are not part of the primary key, or people seem to be dealing with one-to-one or many-to-many relationships. I need to specify the mapping and code so that on insert of the parent, the children get inserted as well. Please help.
My data structure is as follows:
Meeting – parent table
- MeetingID (pk) (int, identity)
- Description
- StartDate
- IsActive
- Venue
MeetingAdministrator – child table
- MeetingID (pk, fk)
- AdminNetworkID (pk) (varchar)
- DateCreated
- IsActive
And here is the Visual Basic .NET source:
<Serializable()> _
Public Class MeetingAdministrator
Private _MeetingID As Integer
Public Overridable Property MeetingID() As Integer
Get
Return _MeetingID
End Get
Set(ByVal value As Integer)
_MeetingID = value
End Set
End Property
Private _AdminNetworkID As String
Public Overridable Property AdminNetworkID() As String
Get
Return _AdminNetworkID
End Get
Set(ByVal value As String)
_AdminNetworkID = value
End Set
End Property
Private _IsActive As Byte
Public Overridable Property IsActive() As Byte
Get
Return _IsActive
End Get
Set(ByVal value As Byte)
_IsActive = value
End Set
End Property
Private _DateCreated As Date
Public Overridable Property DateCreated() As Date
Get
Return _DateCreated
End Get
Set(ByVal value As Date)
_DateCreated = value
End Set
End Property
Private _LastModified As Date
Public Overridable Property LastModified() As Date
Get
Return _LastModified
End Get
Set(ByVal value As Date)
_LastModified = value
End Set
End Property
Private _meeting As Meeting
Public Overridable Property Meeting() As Meeting
Get
Return _meeting
End Get
Set(ByVal value As Meeting)
_meeting = value
End Set
End Property
Public Overrides Function Equals(ByVal obj As Object) As Boolean
Return MyBase.Equals(obj)
End Function
Public Overrides Function GetHashCode() As Integer
Return MyBase.GetHashCode()
End Function
End Class
Imports Iesi.Collections
Imports Iesi.Collections.Generic
Public Class Meeting
Private _MeetingID As Integer
Private _Description As String
Public Overridable Property MeetingID() As Integer
Get
Return _MeetingID
End Get
Set(ByVal value As Integer)
_MeetingID = value
End Set
End Property
Public Overridable Property Description() As String
Get
Return _Description
End Get
Set(ByVal value As String)
_Description = value
End Set
End Property
Private _StartDate As Date = Now
Public Overridable Property StartDate() As Date
Get
Return _StartDate
End Get
Set(ByVal value As Date)
_StartDate = value
End Set
End Property
Private _IsActive As Byte
Public Overridable Property IsActive() As Byte
Get
Return _IsActive
End Get
Set(ByVal value As Byte)
_IsActive = value
End Set
End Property
Private _DateCreated As Date
Public Overridable Property DateCreated() As Date
Get
Return _DateCreated
End Get
Set(ByVal value As Date)
_DateCreated = value
End Set
End Property
Private _Venue As String
Public Overridable Property Venue() As String
Get
Return _ Venue
End Get
Set(ByVal value As String)
_ Venue = value
End Set
End Property
Private _meetingAdministrator As ISet(Of MeetingAdministrator)
Public Overridable Property MeetingAdministrators() As ISet(Of MeetingAdministrator)
Get
Return _meetingAdministrator
End Get
Set(ByVal value As ISet(Of MeetingAdministrator))
_meetingAdministrator = value
End Set
End Property
Public Overridable Sub AddAdministrator(ByVal meetingAdministrator As MeetingAdministrator)
meetingAdministrator.Meeting = Me
_meetingAdministrator.Add(meetingAdministrator)
End Sub
Public Sub New()
_meetingAdministrator = New HashedSet(Of MeetingAdministrator)()
End Sub
End Class
Here are the mapping files:
<!-- Meeting.hbm.xml -->
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Data"
namespace="Data.Domain" >
<!-- Mapping Information -->
<class name="Meeting" table="Meeting" >
<id name="MeetingID" column="MeetingID" type="int">
<generator class="identity" />
</id>
<property name="Description" />
<property name="StartDate" />
<property name="IsActive" />
<property name="Venue" />
<set name="MeetingAdministrators" table="MeetingAdministrator" inverse="true" lazy="true" cascade="save-update" access="property" >
<key column="MeetingID" foreign-key="MeetingID" />
<one-to-many class="Meeting" />
</set>
</class>
</hibernate-mapping>
<!-- MeetingAdministrator.hbm.xml -->
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Data"
namespace="Data.Domain" >
<!-- Mapping Information -->
<class name="MeetingAdministrator" table="MeetingAdministrator" >
<composite-id>
<key-property name="AdminNetworkID" column="AdminNetworkID" type="string" >
</key-property>
<key-many-to-one name="Meeting" class="Meeting" >
<column name="MeetingID" />
</key-many-to-one>
</composite-id>
<property name="IsActive" />
<property name="DateCreated" />
</class>
</hibernate-mapping>
Got the same error message but it was triggered by a delete. The simple reason was the entry had been deleted before already.
I'm pretty sure you'll need to add a <version/>
property to your MeetingAdministrator
class to have this working propertly. See this article for further discussion.
For anyone having problems with inserts with AutoNumber / AutoIncrement for MySQL use the mapping. I found that the .Identity can be temperamental
Id(x => x.Id).GeneratedBy.Increment();
精彩评论