I defined in my migration one of the columns of my table as unique. If I try to save a record that violates this uniqueness constraint of course I receive an exception:
A duplicate value cannot be inserted into a unique index.
To save the record I'm using the IRepository Create and Update methods, because it does not have a corresponding part. After receiving the exception above I catch it and then I launch AddModelError to stop the saving procedure. Neverthless Orchard gives me another exception after that:
[AssertionFailure: null id in MyModule.Models.MyRecord entry (don't flush the Session after an exception occurs)]
NHibernate.Event.Default.DefaultFlushEntityEventListener.CheckId(Object obj, IEntityPersister persister, Object id, EntityMode entityMode) +267
NHibernate.Event.Default.DefaultFlushEntityEventListener.GetValues(Object entity, EntityEntry entry, EntityMode entityMode, Boolean mightBeDirty, ISessionImplementor session) +95
NHibernate.Event.Default.DefaultFlushEntityEventListener.OnFlushEntity(FlushEntityEvent event) +139
NHibernate.Event.Default.AbstractFlushingEventListener.FlushEntities(FlushEvent event) +448
NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent event) +283
NHibernate.Event.Default.DefaultAutoFlushEventListener.OnAutoFlush(AutoFlushEvent event) +84
NHibernate.Impl.SessionImpl.AutoFlushIfRequired(ISet`1 querySpaces) +471
NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results) +477
NHibernate.Impl.AbstractSessionImpl.List(IQueryExpression queryExpression, QueryParameters parameters) +223
NHibernate.Impl.ExpressionQueryImpl.List() +189
NHibernate.Linq.DefaultQueryProvider.ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery query, NhLinqExpression nhQuery) +61
NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) +262
NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) +26
Remotion.Linq.QueryableBase`1.GetEnumerator() +83
System.Linq.Enumerable.ToDictionary(IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer) +173
System.Linq.Enumerable.ToDictionary(IEnumerable`1 source, Func`2 keySelector) +125
Orchard.Data.Migration.DataMigrationManager.GetFeaturesThatNeedUpdate() +311
Orchard.Modules.Data.Migration.<GetNotifications>d__6.MoveNext() +219
System.Linq.<SelectManyIterator>d__14`2.MoveNext() +507
System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +536
System.Linq.Enumerable.ToList(IEnumerable`1 source) +80
Orchard.UI.Admin.Notification.NotificationManager.GetNotifications() +151
Orchard.UI.Admin.Notification.AdminNotificationFilter.OnResultExecuting(ResultExecutingContext filterContext) +380
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +245
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +890
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +890
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +890
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +890
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +97
System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +241
System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +19
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +51
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
Orchard.Mvc.Routes.HttpAsyncHandler.EndProcessRequest(IAsyncResult result) +95
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288
If I understand correctly what is causing it, Orchard automatically tries to flush the record into the database even if I add a model error. I tried to change the transaction scope but it didn't work. Is there a way to solve this problem?
You can't use Unique
constraint when dealing with content part records. The reason is that those are created early, when no data has been passed to it yet (with all properties being empty/null). This happens inside ContentManager
. Hence, all properties on those kinds of records need to be nullable and non-unique.
But you can use the unique/not-null constraints on classes that are mapped to records you create and use via IRepository
directly.