1

I have this mapping

 public class CountryMapping : ClassMap<Country>
    {
        public CountryMapping()
        {
            Id(x => x.Id).GeneratedBy.GuidComb();
            Map(x => x.Name).Not.Nullable().NvarcharWithMaxSize();
            HasMany(x => x.Cards).Cascade.Delete().Inverse();
        }
    }

      public class CardMapping : ClassMap<Card>
    {
        public CardMapping()
        {
            Id(x => x.Id).GeneratedBy.GuidComb();
            Map(x => x.Name).Not.Nullable().NvarcharWithMaxSize(); ;
            References(x => x.Country).Not.Nullable();
            HasMany(x => x.RewardTiers).Cascade.All();
        }
    }

Now I want to delete a country. If you delete a country all the cards should be deleted. It should delete all the rewards.

nhibernateRepo.Load<Country>(countryId);
nhibernateRepo.Delete<Country>(country);
unitOfWork.Commit();

When I do this. I get the following error.

NHibernate.Exceptions.GenericADOException was caught
  Message=could not delete collection: [Domain.Card.RewardTiers#7abaade7-4653-456f-8840-9fc700fa949b][SQL: UPDATE [RewardTier] SET Card_id = null WHERE Card_id = @p0]
  Source=NHibernate
  SqlString=UPDATE [RewardTier] SET Card_id = null WHERE Card_id = @p0
  StackTrace:
       at NHibernate.Persister.Collection.AbstractCollectionPersister.Remove(Object id, ISessionImplementor session)
       at NHibernate.Action.CollectionRemoveAction.Execute()
       at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
       at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
       at NHibernate.Engine.ActionQueue.ExecuteActions()
       at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
       at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
       at NHibernate.Impl.SessionImpl.Flush()
       at NHibernate.Transaction.AdoTransaction.Commit()
       at CCRecomendator.Framework.Data.UnitOfWork.Commit() in UnitOfWork.cs:line 52
       at CCRecomendator.Framework.Services.CountryService.DeleteCountry(Guid countryId) in CountryService.cs:line 157
  InnerException: System.Data.SqlClient.SqlException
       Message=Cannot insert the value NULL into column 'Card_id', table 'cc.dbo.RewardTier'; column does not allow nulls. UPDATE fails.
The statement has been terminated.
       Source=.Net SqlClient Data Provider
       ErrorCode=-2146232060
       Class=16
       LineNumber=1
       Number=515
       Procedure=""
       Server=(local)
       State=2
       StackTrace:
            at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
            at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
            at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
            at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
            at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
            at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
            at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
            at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
            at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
            at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd)
            at NHibernate.Persister.Collection.AbstractCollectionPersister.Remove(Object id, ISessionImplementor session)
       InnerException: 

Why is it trying to do an update when a delete had happened?

JasonS
  • 23,480
  • 9
  • 41
  • 46
chobo2
  • 83,322
  • 195
  • 530
  • 832

1 Answers1

1

It is trying to do an update because it thinks that Card is the "owner" of the Country->Cards association and so when a Country is deleted, NH thinks that it needs to null Country references. This is caused by the Inverse mapping modifier. According to the documentation for Inverse:

Inverse the ownership of this entity. Make the other side of the relationship responsible for saving.

Try removing Inverse from HasMany(x => x.Cards).Cascade.Delete().Inverse();

eulerfx
  • 36,769
  • 7
  • 61
  • 83
  • Hmmmm.It works now. I especially added that before posting as I was getting an error(not sure if it was for this deletion or when I was writing the code to update country). They seem to work now, but I don't have any Inverse on either side. Not sure if I need one or not since. Who knows if no something else broke. This inverse always gets me. – chobo2 Dec 29 '11 at 23:16
  • Yeah it gets me all the time too, it would be helpful if the documentation was more clear. – eulerfx Dec 29 '11 at 23:23
  • 2
    I just wish you would not have to worry about it at all :) – chobo2 Dec 29 '11 at 23:41
  • This is the most helpful comment I've heard on the matter (for one-to-many): "the only case where you wouldn't want to set inverse = true is where it does not make sense for the child to be responsible for updating itself, such as in the case where the child has no knowledge of its parent." So always mark a HasMany as Inverse, unless the child has no knowledge of the parent. In your case, the RewardTiers doesn't have knowledge of the parent card? – Ted Oct 04 '13 at 21:43