Свободный NHibernate - Обновление класса в иерархии TPC - PullRequest
1 голос
/ 22 июня 2011

В данной ситуации, когда у меня есть несколько классов, которые наследуются от базового класса, в иерархии 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.Employees и dbo.Managers - это разные таблицы. Как я могу перейти с более низкого класса на более высокий, не теряя все, что связано с существующим?

1 Ответ

1 голос
/ 23 июня 2011

К сожалению, я не могу придумать способ аккуратно выполнить это обновление - поскольку вы используете Table Per Concrete Class, единственный способ, которым я могу придумать, - это удалить существующего Employee и добавить нового Manager. *

Сказав это, у меня есть кое-что, что может вам помочь - мне это нужно по другой причине, но это может помочь и в вашем случае.

В приведенном ниже классе используется отражение для предоставления общего механизма «копирования». Чтобы использовать его, попробуйте следующий фрагмент кода (при условии, что сотрудник получает повышение по службе):

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

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...