在我有多个继承自基类的类的情况下,在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
是不同的表格。如何从较低级别升级到较高级别而不会丢失现有的所有内容?
答案 0 :(得分: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);
}
}
}
}
希望这有帮助!