例外が発生した後にセッションをフラッシュしない-NHibernate
-
10-07-2019 - |
質問
.NET 3.5、NHibernateでASP.NET MVC Webアプリを開発し、Windows Azureでホストしています。 webappがローカル開発ファブリックから実行されると、正常に動作します。それでも、Windows Azureに移動すると、MVC Webロールから実行されるすべての挿入は、以下にリストされている例外で終わります。
NHibernateロジックの何が問題なのでしょうか? (セッション管理かもしれませんが、わかりません)
[AssertionFailure:Lokad.Translate.Entities.Userエントリのnull id(例外が発生した後にセッションをフラッシュしないでください)] NHibernate.Event.Default.DefaultFlushEntityEventListener.CheckId(Object obj、IEntityPersister persister、Object id、EntityMode entityMode)+292 NHibernate.Event.Default.DefaultFlushEntityEventListener.GetValues(オブジェクトエンティティ、EntityEntryエントリ、EntityMode entityMode、Boolean mightBeDirty、ISessionImplementorセッション)+93 NHibernate.Event.Default.DefaultFlushEntityEventListener.OnFlushEntity(FlushEntityEvent event)+158 NHibernate.Event.Default.AbstractFlushingEventListener.FlushEntities(FlushEvent event)+469 NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent event)+339 NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)+85 NHibernate.Impl.SessionImpl.Flush()+275 NHibernate.Transaction.AdoTransaction.Commit()+236 Lokad.Translate.Repositories.PageRepository.Create(ページページ) Lokad.Translate.Controllers.PagesController.Create(ページページ) lambda_method(ExecutionScope、ControllerBase、Object [])+69 System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext、IDictionary
2 parameters) +251 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary
2 parameters)+31 System.Web.Mvc。<!> lt; <!> gt; c__DisplayClassa.b__7()+88 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter、ActionExecutingContext preContext、Func1 continuation) +534 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList
1 filters、ActionDescriptor actionDescriptor、IDictionary`2 parameters)+312 System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext、String actionName)+856 System.Web.Mvc.Controller.ExecuteCore()+185 System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext)+221 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()+586 System.Web.HttpApplication.ExecuteStep(IExecutionStep step、Boolean <!> amp; completedSynchronously)+177
_session.FlushMode = FlushMode.Commit;
を使用していること、およびUser
がカスタムRoleProvider
public class SimpleRoleProvider : RoleProvider
{
readonly UserRepository Users = new UserRepository();
public override string[] GetRolesForUser(string username)
{
try
{
var user = Users.Get(username);
// no role if user is not registered
if (null == user) return new string[0];
// default role for registered user
return user.IsManager ? new[] { "Manager", "User" } : new[] { "User" };
}
catch (Exception)
{
// role should not fail in case of DB issue.
return new string[0];
}
}
}
解決 2
ついに自分の問題の解決策を見つけました。人々が興味を持っている場合のために、私はここに解決策を投稿しています。
public class SimpleRoleProvider : RoleProvider
{
// isolated session management for the RoleProvider to avoid
// issues with automated management of session lifecycle.
public override string[] GetRolesForUser(string username)
{
using (var session = GlobalSetup.SessionFactory.OpenSession())
{
var users = new UserRepository(session);
var user = users.Get(username);
// no role if user is not registered
if (null == user) return new string[0];
// default role for registered user
return user.IsManager ? new[] {"Manager", "User"} : new[] {"User"};
}
}
}
基本的には、RoleProvider
リポジトリのライフサイクルは通常のインビュー/コントローラ内のリポジトリと同じではないようです。その結果、RoleProviderが呼び出された時点で、NHibernateセッションは既に破棄されており、上記の例外が発生しています。
上記のコードを次のコードに置き換えました。これには独自のNHibernateセッション管理があり、最終的には正常に動作します。
他のヒント
NHibernateトランザクション中に例外をキャッチして無視しないでください。
理由を説明しようとしています。
たとえば、データベースの制約が原因で例外が発生する可能性があります。 (マッピングの問題、プロパティなどによってスローされた例外によっても発生する可能性があります。)NHibernateはメモリ内の状態をデータベースと同期しようとします。これはコミット時に行われます-実際のデータに対してクエリが実行されることを確認するためにクエリの前に実行される場合があります。この同期が失敗すると、データベースの状態はランダムになります、一部の変更は保持され、他の変更は保持されません。このような場合にできることは、セッションを閉じることだけです。
コードの決定と計算はメモリ内の値に基づいていることを考慮してください。しかし、無視された例外の場合、この値はデータベース内の値ではなく、決して存在しません。したがって、ロジックは「ファンタジーデータ」を決定して計算します。
ところで、例外(型指定なし)をキャッチして無視することはお勧めできません。処理する例外を常に把握し、続行できることを確認してください。
ここでやっていることは、プログラミングエラーを飲み込むことです。私を信じて、システムはこれ以上安定しないでしょう。問題は、エラーが発生したときに気づくのか、そこでエラーを無視し、エラーの結果をデータベースに保持するだけですか?後者の場合、データベースに一貫性がなく、データベースからデータを取得しようとするときに他のエラーが発生しても驚かないでください。そして、エラーの実際の原因であるコードを見つけることは決してありません。
この例外は、列名に予約語が含まれている場合に発生する可能性があります(たとえば、列名としてstatusを使用すると、保存できなくなります)