我的会话使用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创建添加更改通知功能的代理。这意味着所有我的对象来自DB作为Castle Proxies,它是AFAIK透明的。
每当我将其中一个NH生成的MVVM代理传递到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);
}
答案 0 :(得分: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);
}
答案 1 :(得分:0)
article and sample code(拦截实体创建)演示使用动态代理实现(WPF)更改通知。如你所见,你必须在NHibernate和外部使用相同的代理生成器来实现NHibernate代理的识别(参见类DataBindingIntercepter方法GetEntityName)。
为什么我必须在外部创建的实例的拦截器中添加识别逻辑(请参阅下面的代码),而在内部创建的实例可以保持原样?
ISession上的方法只将实例添加到字典中以在Flush上搜索脏实例。由于加载的所有实例都自动成为此字典的一部分,因此会话立即“知道”该实体并且在SaveOrUpdate中不执行任何操作。对于来自外部的其他实例,首先必须获取适当的映射(使用默认为类fullname的entitiyname)以了解哪些属性构成主键。