Let me begin with showing the mapping:
Parent:
<bag name="Communicatiekanalen" table="COMMUNICATIEKANAAL" inverse="true" cascade="delete" lazy="true" >
<key column="SEK_PROFIEL"/>
<one-to-many class="Crm.Hibernate.Communicatiekanaal,Crm.Hibernate" />
</bag>
Child:
<many-to-one name="SekProfiel" column="SEK_PROFIEL" class="Crm.Hibernate.Profiel,Crm.Hibernate" />
In other words: a profile can have many communication channels.
On the UI (user-interface [ASP.NET Webforms]) the following event is fired (deleting a profile with communication channels attached to it) :
var profielDao = CrmConfiguration.GetDaoFactory().GetProfielDao();
var profiel = profielDao.GetById(2194, true); //lets say '2194' is an ID that exists
profielDao.Delete(profiel);
(the DaoFactory is located in one project file and the UI is an ASP.NET Website)
This code works.
IMPORTANT: the code is using the NHibernate 'open-session-in-view' pattern.
I have a service implementation that fires the same code (deleting a profile with communication channels). Some code...
var daof = CrmConfiguration.GetDaoFactory();
CrmSettings.Instance.UserID = user;
var profielDao = daof.GetProfielDao();
profielDao.BeginTransaction();
var profiel = profielDao.GetById(CrmEntitiesToHibernate.ParseStringToId(profileId), true);
profielDao.Delete(profiel);
profielDao.EndTransaction();
Where 'EndTransaction()' does a 'commit'. I test this code with an 'unit test':
[TestMethod]
public void TestDeleteProfile()
{
//Getting a valid NEW profile
var profile = GetSecundaryProfile();
//Adding a communication channel to the profile
CrmClient.AddCommunicationChannelForProfile(GetPlainCommunicationChannel(), profile.Id, CurrentUserId);
//Calling the 'delete profile' method on the service --> FAIL - no cascade
CrmClient.DeleteProfile(profile.Id, CurrentUserId);
}
This code fails. The following error is bugging me:
The DELETE statement conflicted with the REFERENCE constraint "R2_PROFIEL". The conflict occurred in database "CRM_ontw", table "dbo.COMMUNICATIEKANAAL", column 'SEK_PROFIEL'. The statement has been terminated.
This means that the cascade didn't happen at all. Executed from the UI it works, but when fired from the 'service implementation', it fails. Any ideas or suggestions that could help me?
Thanks in advance
Edit: the following generic code delete's an object
public void Delete(T entity)
{
try
{
OnDelete(entity);
开发者_如何学C }
catch (Exception)
{
SessionManager.Instance.RollbackTransactionOn(SessionFactoryConfigPath);
throw;
}
session.Delete(entity);
}
Setting the all-delete-orphan
doesn't fix the problem.
I've found the problem. The NHibernate 'open-session-in-view' pattern closes the session after commiting the changes to the database (so when the requests ends, the sessions gets closed):
finally
{
// No matter what happens, make sure all the sessions get closed
foreach (SessionFactoryElement sessionFactorySettings in openSessionInViewSection.SessionFactories)
{
SessionManager.Instance.CloseSessionOn(sessionFactorySettings.FactoryConfigPath);
}
}
But my EndTransaction()
implementation on the service side didn't.
So with a few tweaks I created this EndTransaction()
method:
public void EndTransaction()
{
try
{
SessionManager.Instance.CommitTransactionOn(SessionFactoryConfigPath);
}
finally
{
SessionManager.Instance.CloseSessionOn(SessionFactoryConfigPath);
}
}
Try setting cascade="delete"
to cascade="all-delete-orphan"
Also, ensure that in both instances, the parent is being read and saved by the same ISession
instance. As someone commented, we need to see the implementation of your .Delete()
method.
精彩评论