2011-06-22 28 views
1

在给定的情况下,我有一个基类继承的多个类,在Table Per Concrete Class层次结构中,我有一种情况,可能需要将一个类“升级”一个较低的水平到一个更高的水平。Fluent NHibernate - 升级TPC层次结构中的类

作为示例,我将使用类Employee - >Manager演示。

class Employee { 
    Guid Id { get; set; } 
    // certain properties 
} 

class Manager : Employee { 
    // certain unique properties 
} 

EmployeeMap : ClassMap<Employee> { 
    // mapping information 
} 
ManagerMap : SubClassmap<Manager> { 
    // appropriate unique properties mapping 
} 

var employee = new Employee { 
    Name = "Some Employee" 
} 

session.Save(employee); 

喂,一会儿后,那Employee被碰着Manager,所以现在我该怎么办? dbo.Employeesdbo.Managers是不同的表格。我怎样才能从一个较低的班级升级到一个更高的班级,而不会失去所有现有的东西?

回答

1

不幸的是,我想不出任何方法来整齐地执行这个更新 - 因为你使用Table Per Concrete Class,我能想到的唯一方法是删除现有的Employee并添加一个新的Manager。说了这么多,我确实有一些可以帮助你的东西 - 我需要它的原因是不同的,但它也可能对你有帮助。

下面的类使用反射来提供通用的“复制”机制。要使用它,试试下面的代码片段(假设员工是员工获得晋升):

var manager = new Manager; 
var copier = new PropertyCopier<Employee,Manager>(employee, manager); 
copier.Copy(); 

经理对象现在应具有相同的属性值Employee对象做了(至少在财产存在于两个类)。现在您可以提交经理并删除原始员工。

的PropertyCopier类代码如下:

using System; 
using System.Reflection; 

// ... You will want this in your own namespace not mine. ;-) 

///<summary> 
/// Copies properties with the same name and type from one object to another. 
///</summary> 
///<typeparam name="TFirst">The object type to copy from.</typeparam> 
///<typeparam name="TSecond">The object type to copy to.</typeparam> 
public class PropertyCopier<TFirst, TSecond> 
    where TFirst : class 
    where TSecond : class 
{ 
    private readonly TFirst _first; 
    private readonly TSecond _second; 

    ///<summary> 
    /// Creates an instance of the PropertyCopier. 
    ///</summary> 
    ///<param name="first">The object to copy properties from.</param> 
    ///<param name="second">The object to copy properties to.</param> 
    ///<exception cref="ArgumentNullException">An <see cref="ArgumentNullException"/> will be thrown if 
    /// the source or destination objects are null.</exception> 
    public PropertyCopier(TFirst first, TSecond second) 
    { 
     if (first == null) 
     { 
      throw new ArgumentNullException("first"); 
     } 

     if (second == null) 
     { 
      throw new ArgumentNullException("second"); 
     } 

     _first = first; 
     _second = second; 
    } 

    ///<summary> 
    /// Performs the copy operation. 
    ///</summary> 
    public void Copy() 
    { 
     Copy(p => true); 
    } 

    ///<summary> 
    /// Performs the copy operation, omitting any items for which the predicate evaluates to false. 
    ///</summary> 
    ///<param name="predicate">A predicate based on the <see cref="PropertyInfo"/> used to determine if the property should be copied.</param> 
    ///<exception cref="ArgumentException">An <see cref="ArgumentException"/> may be thrown if the copy cannot be performed. 
    /// This may happen if, for example, there is a property with the same name but a different type.</exception> 
    public void Copy(Predicate<PropertyInfo> predicate) 
    { 
     foreach (PropertyInfo info in typeof(TFirst).GetProperties()) 
     { 
      PropertyInfo infoInDestination = null; 

      try 
      { 
       infoInDestination = typeof(TSecond).GetProperty(info.Name, info.PropertyType); 
      } 
      catch (AmbiguousMatchException) 
      { 
      } 

      try 
      { 
       if (infoInDestination != null && infoInDestination.CanWrite && predicate(infoInDestination)) 
       { 
        infoInDestination.SetValue(_second, info.GetValue(_first, null), null); 
       } 
      } 
      catch (Exception e) 
      { 
       throw new ArgumentException(String.Format("Unable to copy property called {0}", info.Name), e); 
      } 
     } 
    } 
} 

希望这有助于!

+0

谢谢,这实际上工作非常好! – Ciel