C# – NHibernate : object references an unsaved transient instance

cfluent-nhibernatenhibernate

When I try to add an object to a repository I get the NHibernate.TransientObjectException with message:

object references an unsaved transient instance – save the transient instance before flushing or set cascade action for the property to something that would make it autosave.
Type: MyApp.Domain.Model.Task

I use:

  • NHibernate 3.3.1
  • FluentNHibernate 1.4
  • Microsoft Unity 2.1.505

The method in the repository is more or less as follows (I present here a merged version):

public void Add(T item)
{
    if (!GetSession().Query<T>().Contains(item)) //generates the error, if commented out works fine
    {
        try
        {
            GetSession().BeginTransaction();
            GetSession().Save(item);
            GetSession().CommitTransaction();
        }    
        catch
        {
            //rollback code
        }
    }
}

The important thing is that the object I try to save in the repository does not have any references and/or relations to other objects. It is a rather simple entity.
What is worth mentioning that it extends the DomainObject which has Guid type ID.

I use the Code First schema, so my DB is generated based on my code.
Because of inheritance (every entity extends DomainObject) I use UseUnionSubclassForInheritanceMapping()

The whole stack trace is as follows:

   w NHibernate.Engine.ForeignKeys.GetEntityIdentifierIfNotUnsaved(String entityName, Object entity, ISessionImplementor session)
   w NHibernate.Type.EntityType.GetIdentifier(Object value, ISessionImplementor session)
   w NHibernate.Type.ManyToOneType.NullSafeSet(IDbCommand cmd, Object value, Int32 index, ISessionImplementor session)
   w NHibernate.Param.NamedParameterSpecification.Bind(IDbCommand command, IList`1 multiSqlQueryParametersList, Int32 singleSqlParametersOffset, IList`1 sqlQueryParametersList, QueryParameters queryParameters, ISessionImplementor session)
   w NHibernate.Param.NamedParameterSpecification.Bind(IDbCommand command, IList`1 sqlQueryParametersList, QueryParameters queryParameters, ISessionImplementor session)
   w NHibernate.SqlCommand.SqlCommandImpl.Bind(IDbCommand command, ISessionImplementor session)
   w NHibernate.Loader.Loader.PrepareQueryCommand(QueryParameters queryParameters, Boolean scroll, ISessionImplementor session)
   w NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
   w NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
   w NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)
   w NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters)
   w NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes)
   w NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader.List(ISessionImplementor session, QueryParameters queryParameters)
   w NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, QueryParameters queryParameters)
   w NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results)
   w NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results)
   w NHibernate.Impl.AbstractSessionImpl.List(IQueryExpression queryExpression, QueryParameters parameters)
   w NHibernate.Impl.ExpressionQueryImpl.List()
   w NHibernate.Linq.DefaultQueryProvider.ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery query, NhLinqExpression nhQuery)
   w NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
   w NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
   w System.Linq.Queryable.Contains[TSource](IQueryable`1 source, TSource item)
   w MyApp.Data.Nhibernate.Fluent.Repository`1.Add(T item) w f:\Projects\MyApp\MyApp.Data.Nhibernate.Fluent\Repository.cs:wiersz 75
   w MyApp.Domain.Services.Impl.CatalogServices.CreateTask(Task task) w f:\Projects\MyApp\MyApp.Domain.Services\Impl\CatalogServices.cs:wiersz 51

I would appreciate your help

Best Regards,
Sebastian

Best Answer

You simply cannot query an object which is unsafed because it has no ID assigned.

To query for that entity, NHibernate will try to figure out the ID of the entity. This only works on saved or transient objects which are saved.

Not saved entities do not have an ID set. So if the type of the ID is int, value would be zero. In your case I guess it will be Guid.Empty because Guid cannot be null. Just check for that instead.

You can also define the unsafed value within the mapping to be 100% sure ;). But it should also work by default with Guid or int. The mapping can be used for custom types etc...

Id(x => x.Id).UnsavedValue(0);