2013-08-16 172 views
1

我试图在OnPostUpdate事件中获取更新实体的旧状态。 @event参数的OldState属性将对象作为数组返回,我需要它作为对象。我试过如下:NHibernate事件侦听深克隆对象

public class EventListener : IPostUpdateEventListener { 
    public void OnPostUpdate(PostUpdateEvent @event) { 
     // Get the property names to align with the indexes of the old state 
     var propertyNames = @event.Persister.PropertyNames; 

     // Get the original entity values 
     var type = @event.Entity.GetType(); 
     var original = Activator.CreateInstance(type); 

     // Set the values 
    for (var i = 0; i < @event.OldState.Length; i++) { 
     // Get the property and value 
     var property = type.GetProperty(@event.Persister.PropertyNames[i]); 
     var value = @event.OldState[i]; 

     if (property.CanWrite && !(@event.Persister.PropertyTypes[i] is CollectionType)) { 
      if (value != null && (@event.Persister.PropertyTypes[i] is ComponentType || @event.Persister.PropertyTypes[i] is EntityType)) 
       property.SetValue(original, CloneObject(value)); 
      else 
       property.SetValue(original, value); 
     } 
    } 
} 

这里的CLONEOBJECT方法:

private object CloneObject(object source) { 
    var sourceType = source.GetType(); 
    var target = Activator.CreateInstance(sourceType, true); 

    foreach (var property in type.GetProperties()) { 
     var value = property.GetValue(source, null); 

     if (property.CanWrite && (property.PropertyType == typeof(string) || !typeof(IEnumerable).IsAssignableFrom(property.PropertyType)) && !property.PropertyType.IsInterface) { 
      if (value != null && typeof(IEntity).IsAssignableFrom(property.PropertyType)) 
       property.SetValue(target, CloneObject(value)); 
      else 
       property.SetValue(target, value); 
     } 
    } 

    return target; 
} 

我做的第一件事是环比在原来的对象的属性,然后我试图处理组件和引用类型(忽略列表)。这会正确复制对象。然而,随后引发错误:

collection [Models.ContentType.Tags] was not processed by flush()

编辑:将contentType类是我更新的属性的一个类型。这是它的实施,因为它帮助:

public class ContentType : Entity<int> { 
    public virtual string Name { get; set; } 

    public virtual IList<ContentTag> Tags { get; set; } 

    public ContentType() { 
     Tags = new List<ContentTag>(); 
    } 
} 

我也遇到类似的错误,当我试图让其他实体的旧状态。如果有人能告诉我正确的方式来做到这一点,我会很感激。由于

+0

您遇到了什么问题? –

+0

每当它更新实体时,我都会收到错误“集合[Models.User.Addresses]未由flush()处理”。 – nfplee

回答

1

编辑

虽然你似乎并不被触及任何集合,在这个问题:

Collection was not processed by flush when iterate through collection in PostUpdateEvent

你可以试用一下这个答案,以确保它是不是原因

https://stackoverflow.com/a/11575172/1236044


:您的问题

知道触发错误的行会真的有帮助。

又是什么CloneObjectproperty.SetValue(target, CloneObject(value));

你有没有试过移动两条线var value = ...里面对应的if声明?这样你只有在真正需要的时候才能处理这个值。

var value = @event.OldState[i]; 

    if (property.CanWrite && !(@event.Persister.PropertyTypes[i] is CollectionType)) { 
     if (value != null && (@event.Persister.PropertyTypes[i] is ComponentType || @event.Persister.PropertyTypes[i] is EntityType)) 

成为

if (property.CanWrite && !(@event.Persister.PropertyTypes[i] is CollectionType)) { 
     var value = @event.OldState[i]; 
     if (value != null && (@event.Persister.PropertyTypes[i] is ComponentType || @event.Persister.PropertyTypes[i] is EntityType)) 

var value = property.GetValue(source, null); 

    if (property.CanWrite && (property.PropertyType == typeof(string) || !typeof(IEnumerable).IsAssignableFrom(property.PropertyType)) && !property.PropertyType.IsInterface) { 
     if (value != null && typeof(IEntity).IsAssignableFrom(property.PropertyType)) 

成为

if (property.CanWrite && (property.PropertyType == typeof(string) || !typeof(IEnumerable).IsAssignableFrom(property.PropertyType)) && !property.PropertyType.IsInterface) { 
     var value = property.GetValue(source, null); 
     if (value != null && typeof(IEntity).IsAssignableFrom(property.PropertyType)) 
+0

谢谢我更新了我的问题。 CloneObject是私有方法的正确名称。我正在合并来自早期版本的新解决方案,并且错过了重命名其中一个事件。不过,我已经按照你的说法做了,但问题仍然存在。我用ContentType类编辑了我的问题,该类是我正在更新的实体的属性。 – nfplee

+0

@nfplee用一些(也许)有趣的链接编辑我的答案 – jbl

+0

谢谢我将修补程序应用于IFlushEventListener并清除了此错误。然而,我后来又遇到了另一个问题。既然它不是原始问题的一部分,我会将其标记为答案。谢谢 – nfplee