0

私のセッションでは、NHInterceptor を使用して INotifyPropertyChanged サポートをモデルに追加します。

// I use the session generated here to fetch Data
public class SessionServiceImpl : ISessionService
{
    [Inject]
    public ISessionFactory SessionFactory { get; set; }

    [Inject]
    public NhChangeNotificationInterceptorImpl ChangeNotificationInterceptor { get; set; }

    public ISession GetSession() // reduced code here
    {
        return SessionFactory.OpenSession(ChangeNotificationInterceptor);
    }
}

// This is the interceptor implementation
public class NhChangeNotificationInterceptorImpl : EmptyInterceptor, IInterceptor
{
    [Inject]
    public ISessionFactory SessionFactory { get; set; }

    [Inject]
    public ViewModelProxyFactory ProxyFactory { get; set; }

    public override object Instantiate(string entityTypeName, EntityMode entityMode, object id)
    {
        Type type = Type.GetType(entityTypeName); 

        if (type == null) { /* Throw Exception*/ }
        bool isViewModel = false;
        while (type != typeof(object))
        {
            Type tempType = type.BaseType;
            if (tempType == typeof(ViewModelBase))
            {
                isViewModel = true;
                break;
            }
        }

        if (entityMode == EntityMode.Poco && isViewModel)
        {
            var instance = ProxyFactory.CreateProxy(type);
            SessionFactory.GetClassMetadata(entityTypeName).SetIdentifier(instance, id, entityMode);
            return instance;
        }
        return base.Instantiate(entityTypeName, entityMode, id);
    }
}

ProxyFactory は Castle を使用して、変更通知機能を追加するプロキシを作成します。つまり、私のすべてのオブジェクトは、知る限り透過的な Castle Proxies として DB から取得されます。

これらの NH 生成 MVVM プロキシの 1 つを に渡すとSession.Save()、すべて問題ありません。

さて、データ ドリブン アプリケーションの進行に伴い、新しいインスタンスを作成して保存する必要もあります。モデル タイプのインスタンスを作成し、セッションを介して問題なく保存できます。MVVM プロキシ インスタンスを作成し (Ninject を使用して、同じ SessionFactory および ProxyFactory インスタンスが全体で使用されるようにします)、これをスローするSession.Save()と、次のようになります。


"NHibernate.MappingException".
  Message=No persister for: Castle.Proxies.FieldDescriptionProxy
  Source=NHibernate
  StackTrace:
       at NHibernate.Impl.SessionFactoryImpl.GetEntityPersister(String entityName)
       at NHibernate.Impl.SessionImpl.GetEntityPersister(String entityName, Object obj)
       at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
       at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
       at NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
       at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
       at NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
       at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
       at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
       at NHibernate.Impl.SessionImpl.Save(Object obj)
       at Interpretation.UI.Service.Impl.Dao.FieldDao.SaveFields(IList`1 fields, ISession session) in C:\...\FieldDao.cs:Zeile 51.
  InnerException: 

ここで何がうまくいかないのか(または私が忘れていた可能性があるもの)はありますか?

編集:これで機能しましたが、内部で作成されたインスタンスはそのまま保持できるのに、外部で作成されたインスタンスのインターセプターに認識ロジック (以下のコードを参照) を追加する必要があるのはなぜですか?

    public override string GetEntityName(object entity)
    {
        Type type = entity.GetType();
        if (type.FullName.StartsWith("Castle.Proxies") &&
            type.FullName.EndsWith("Proxy"))
        {
            return type.BaseType.FullName;
        }
        return base.GetEntityName(entity);
    }
4

2 に答える 2

2

GetEntityName メソッドを実装するとうまくいきました。

public override string GetEntityName(object entity)
{
    Type type = entity.GetType();
    if (type.FullName.StartsWith("Castle.Proxies") &&
        type.FullName.EndsWith("Proxy"))
    {
        return type.BaseType.FullName;
    }
    return base.GetEntityName(entity);
}
于 2012-12-17T15:02:37.747 に答える
0

動的プロキシを使用して (WPF) 変更通知を実装する方法を示す記事とサンプル コード(Intercepting Entity Creation)。そこに見られるように、NHibernate のプロキシの認識を実装するには、NHibernate と外部で同じプロキシ ジェネレータを使用する必要があります (クラス DataBindingIntercepter メソッド GetEntityName を参照)。

内部で作成されたインスタンスはそのまま保持できるのに、外部で作成されたインスタンスのインターセプターに認識ロジック (以下のコードを参照) を追加する必要があるのはなぜですか?

ISession のメソッドは、インスタンスをディクショナリに追加して、Flush でダーティなインスタンスを検索するだけです。ロードされたすべてのインスタンスは自動的にこのディクショナリの一部になるため、セッションはすぐにエンティティを「認識」し、SaveOrUpdate で何もしません。外部から来る他のインスタンスの場合、最初に適切なマッピングを取得して (クラスのフルネームにデフォルト設定されるエンティティ名を使用)、どのプロパティが主キーを形成するかを知る必要があります。

于 2012-11-05T09:18:22.193 に答える