作業中の MVC 2 プロジェクトでファミリ名のリストに関連付けられた顧客を保存しようとすると、NHibernate が TransientObjectException をスローするという問題が発生します。
これはクラスのコードです:
public class Customer
{
public virtual Guid Id { get; set; }
public virtual int Version { get; set; }
public virtual string Forename { get; set; }
public virtual IList<FamilyName> FamilyNames { get; set; }
}
public class FamilyName
{
public virtual Guid Id { get; set; }
public virtual int Version { get; set; }
public virtual string Name{ get; set; }
public virtual bool IsCurrent { get; set; }
public virtual Patient Patient { get; set; }
}
永続化のために Fluent NHibernate を使用しています。マッピングは次のようになります。
public CustomerMap()
{
Table("Customers");
Id(x=>x.Id).GeneratedBy.GuidComb();
Version(x => x.Version);
Map(x => x.Forename).Not.Nullable();
HasMany(x => x.FamilyNames)
.Inverse()
.Cascade.All();
}
public FamilyNameMap()
{
Table("FamilyNames");
Id(x=>x.Id).GeneratedBy.GuidComb();
Version(x => x.Version);
Map(x => x.Name).Not.Nullable();
Map(x => x.IsCurrent).Not.Nullable();
References(x => x.Patient).Not.Nullable();
}
次のコードを含む厳密に型指定された EditCustomerDetails ビューがあります。
<% using (Html.BeginForm("SaveChanges", "CustomerDetails")) { %>
<input type="submit" value="Save changes"/>
<%= Html.HiddenFor(customer => customer.Id) %>
<%= Html.HiddenFor(customer => customer.Version) %>
<label>Forename:</label>
<%= Html.TextBoxFor(customer => customer.Forename)%>
<label>Family Names</label>
<div class="familyNames">
<%= Html.EditorFor(customer => customer.FamilyNames)%>
</div>
<% } %>
これは、FamilyName クラスのカスタム エディター テンプレートです。
<%= Html.HiddenFor(name => name.Id) %>
<%= Html.HiddenFor(name => name.Version) %>
<%= Html.HiddenFor(name => name.Patient.Id) %>
<label>Name:</label>
<%= Html.TextBoxFor(name => name.Name) %>
<label>Is Current?:</label>
<%= Html.CheckBoxFor(name =>name.IsCurrent) %>
[変更を保存] ボタンをクリックすると、コントローラーのメソッドが呼び出され、顧客がリポジトリに戻され、ISession の Update メソッドが呼び出されます。これは、「オブジェクトが保存されていない一時インスタンスを参照しています - フラッシュする前に一時インスタンスを保存してください」というメッセージとともに NHibernate.TransientObjectException がスローされている場所です。
なぜこれが起こっているのか分かりません。コードに足を踏み入れたところ、すべてのデータがビューから正しく返され、すべてのオブジェクトが正しいプロパティ値を持っています。これを修正するために私が見つけた唯一の提案は、とにかく私が行っていたマッピングで Cascade.All を設定することです。
何か案は?
編集:これはエラーメッセージです:
ERROR Shipping.Web.Filters.UnhandledErrorAttribute - An unhandled exception has occurred
Shipping.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing. Type: Shipping.Domain.Entities.Customer, Entity: Haemoglobinopathy.Domain.Entities.Customer
at NHibernate.Engine.ForeignKeys.GetEntityIdentifierIfNotUnsaved(String entityName, Object entity, ISessionImplementor session)
at NHibernate.Type.EntityType.GetIdentifier(Object value, ISessionImplementor session)
at NHibernate.Type.ManyToOneType.NullSafeSet(IDbCommand st, Object value, Int32 index, Boolean[] settable, ISessionImplementor session)
at NHibernate.Persister.Entity.AbstractEntityPersister.Dehydrate(Object id, Object[] fields, Object rowId, Boolean[] includeProperty, Boolean[][] includeColumns, Int32 table, IDbCommand statement, ISessionImplementor session, Int32 index)
at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
at NHibernate.Persister.Entity.AbstractEntityPersister.UpdateOrInsert(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, Object rowId, ISessionImplementor session)
at NHibernate.Action.EntityUpdateAction.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 Haemoglobinopathy.Persistence.TransactionAttribute.OnActionExecuted(ActionExecutedContext filterContext) in C:\dev\Projects\Haemoglobinopathy\Haemoglobinopathy.Persistence\TransactionAttribute.cs:line 26
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassd.<>c__DisplayClassf.<InvokeActionMethodWithFilters>b__c()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassd.<>c__DisplayClassf.<InvokeActionMethodWithFilters>b__c()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)