Fluent NHibernate-升级TPC层次结构中的类

本文关键字:层次结构 TPC NHibernate- 升级 Fluent | 更新日期: 2023-09-27 17:59:50

在给定的情况下,我有多个从基类继承的类,在Table Per Concrete Class层次结构中,我遇到可能需要将类从较低级别"升级"到更高级别的情况。

例如,我将使用类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是不同的表。如何从较低等级升级到较高等级而不丢失现有等级的所有内容?

Fluent NHibernate-升级TPC层次结构中的类

不幸的是,我想不出任何方法来整齐地执行此更新 - 因为您使用的是每个具体类的表,所以我能想到的唯一方法是删除现有员工并添加新经理。

话虽如此,我确实有一些可能对你有帮助的东西 - 我出于不同的原因需要它,但它也可能对你的情况有所帮助。

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

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

经理对象现在应具有与雇员对象相同的属性值(至少在两个类中都存在该属性时(。现在,您可以提交经理并删除原始员工。

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);
            }
        }
    }
}

希望这有帮助!