2011-06-22 4 views
1

Table Per Concrete Class階層で基本クラスから継承する複数のクラスがある特定の状況では、クラスを 'アップグレード'する必要がある場合があります低いレベルから高いレベルへと変化する。流暢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); 

はさて、しばらく後に、そのEmployeeManagerにぶつかっますので、今、私は何ができるのでしょうか? dbo.Employeesdbo.Managersは異なる表です。既存のものをすべて失うことなく、下位クラスから上位クラスにアップグレードするにはどうすればよいですか?

答えて

1

残念ながら、私は考えることができる唯一の方法は、既存の従業員を削除し、新しいマネージャを追加することですが、この更新をうまく実行する方法を考えることはできません。

私はあなたに助けになるものがあると言いました - 私は別の理由でそれを必要としましたが、あなたの場合にも役立つかもしれません。

以下のクラスは、リフレクトを使用して一般的な「コピー」メカニズムを提供します。これを使用するには、次のコードスニペットを試してみてください(従業員が従業員が昇格なっていると仮定した場合):従業員オブジェクトが行ったように

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

・ホープ、このことができます!

+0

ありがとう、これは実際にはきれいにうまくいった! – Ciel

関連する問題