Hi,
I needed to make two changes to AbstractEntityPersister:
1) Made GetGeneratedIdentity virtual/overridable
2) Modified the function Insert by extracting a method so it could be overriden. ie,
Code:
if (sql.CommandType == CommandType.Text)
{
insertSelectSQL = Dialect.AddIdentitySelectToInsert(text, GetKeyColumns(0)[0], GetTableName(0));
}
became
Code:
if (sql.CommandType == CommandType.Text)
{
insertSelectSQL = AddIdentitySelectToInsert(sql.Text);
}
coupled with
Code:
protected virtual SqlString AddIdentitySelectToInsert(SqlString text)
{
return Dialect.AddIdentitySelectToInsert(text, GetKeyColumns(0)[0], GetTableName(0));
}
Here's the persister I use for tables that require it:
Code:
Imports NHibernate
Imports NHibernate.Persister.Entity
Imports NHibernate.Mapping
Imports NHibernate.Cache
Imports NHibernate.Engine
Namespace ORM.Extensions
Public Class CompositeIdentityTablePersister
Inherits NHibernate.Persister.Entity.SingleTableEntityPersister
Public Sub New(ByVal model As PersistentClass, ByVal cache As ICacheConcurrencyStrategy, _
ByVal factory As ISessionFactoryImplementor, ByVal mapping As IMapping)
MyBase.New(model, cache, factory, mapping)
End Sub
Public Overrides ReadOnly Property IdentifierGenerator() As NHibernate.Id.IIdentifierGenerator
Get
Return New NHibernate.Id.IdentityGenerator
End Get
End Property
Public Overrides ReadOnly Property IsIdentifierAssignedByInsert() As Boolean
Get
Return True
End Get
End Property
''' <remarks>
''' We override this so we can return a null identifier if the ID is zero, which allows IsUnsaved in the persister to
''' spot this record needs saving
''' </remarks>
Public Overrides Function GetIdentifier(ByVal obj As Object) As Object
Dim key As DBKey = MyBase.GetIdentifier(obj)
If key Is Nothing OrElse key.ID = 0 Then Return Nothing
Return key
End Function
''' <remarks>
''' Had to modify the base class AbstractEntityPersister to make this overridable
''' </remarks>
Protected Overrides Function GetGeneratedIdentity(ByVal obj As Object, ByVal session As NHibernate.Engine.ISessionImplementor, ByVal rs As System.Data.IDataReader) As Object
Dim id As DBKey = New DBKey
Try
If Not rs.Read() Then Throw New HibernateException("The database returned no natively generated identity value")
id.ID = rs(0)
id.Prefix = rs(1)
Finally
rs.Close()
End Try
Return id
End Function
''' <remarks>
''' Had to extract this method from the Protected Insert method of the AbstractEntityPersister
''' </remarks>
Protected Overrides Function AddIdentitySelectToInsert(ByVal text As NHibernate.SqlCommand.SqlString) As NHibernate.SqlCommand.SqlString
' Need to get the field names for the Prefix and ID columns
Dim IDField As String = If(IdentifierColumnNames(0).EndsWith("ID"), IdentifierColumnNames(0), IdentifierColumnNames(1))
Dim PrefixField As String = If(IdentifierColumnNames(0).EndsWith("ID"), IdentifierColumnNames(1), IdentifierColumnNames(0))
' Also need to identify which parameter contains the passed in prefix
' We'll assume that the first three parts are "INSERT INTO ", tablename and a comma, and that each field is
' separated by a comma
Dim ValPartIndex As Integer = 0, PrefixIndex As Integer = -1
For partindex As Integer = 4 To text.Parts.Count - 1 Step 2
If text.Parts(partindex) = ") VALUES (" Then
ValPartIndex = partindex
Exit For
End If
Next
For partindex As Integer = 3 To ValPartIndex Step 2
If text.Parts(partindex) = "Prefix" Then
PrefixIndex = (partindex - 3) / 2
Exit For
End If
Next
Return text.Append(String.Format("; SELECT SCOPE_IDENTITY() AS {0}, @p{2} AS {1}", IDField, PrefixField, PrefixIndex))
End Function
End Class
End Namespace
and here's an example mapping:
Code:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Domain" assembly="Saturn.DAO">
<class name="Saturn.DAO.Domain.Client, Saturn.DAO" table="Clients" persister="Saturn.DAO.ORM.Extensions.CompositeIdentityTablePersister, Saturn.DAO">
<!-- Identity -->
<composite-id name="ID" class="Saturn.DAO.Types.DBKey">
<key-property name="Prefix"/>
<key-property name="ID"/>
</composite-id>
DBKey is a class that manages the Prefix/ID pair for me
Hope that's some help to you. The solution turned out to be fairly simple, but working my way through the nhibernate code to get to it was somewhat challenging.
Kev