2013-06-29 17 views
6

これは私にとって少し新しいものです。私は、同じテーブルに2つのデータセットを読み込むETLプログラムを書くように求められました。データセット#1が完成し、テーブルのすべてのデータが含まれます。ただし、データセット#2には、の変更のみが含まれ、最初のデータセットにオーバーレイする必要があります。お守り:エンティティフレームワーク - nullでない値のみを更新します。

//データセット#1:ウィジェット表

+----+------+------+------+------+ 
| ID | COL1 | COL2 | COL3 | COL4 | 
+----+------+------+------+------+ 
| 1 | abcd | abcd | abcd | abcd | 
+----+------+------+------+------+ 
| 2 | abcd | abcd | abcd | abcd | 
+----+------+------+------+------+ 

//データセット#2:Widgets_Changes表

+----+------+------+------+------+ 
| ID | COL1 | COL2 | COL3 | COL4 | 
+----+------+------+------+------+ 
| 1 |  | efgh |  | ijkl | 
+----+------+------+------+------+ 
| 2 | mnop |  | qrst |  | 
+----+------+------+------+------+ 

//予想結果:すべての変更とウィジェット

+----+------+------+------+------+ 
| ID | COL1 | COL2 | COL3 | COL4 | 
+----+------+------+------+------+ 
| 1 | abcd | efgj | abcd | ijkl | 
+----+------+------+------+------+ 
| 2 | mnop | abcd | qrst | abcd | 
+----+------+------+------+------+ 

私が避けようとしている明白なアプローチは、各ウィジェットを最初のテーブルから引き出して、プロパティ-bを実行することですY-プロパティの比較:

// Simplified example: 
using (var db = new MyEntityDatabase()){ 

    var widget  = from p in db.Widgets select p where p.ID == 1; 
    var widget_diff = from p in db.Widgets_Changes select p where p.ID == 1 

    widget.COL1 = widget_diff.COL1 ?? widget.COL1; 
    widget.COL2 = widget_diff.COL2 ?? widget.COL2; 
    widget.COL3 = widget_diff.COL3 ?? widget.COL3; 
    // ...etc 

    db.saveChanges(); 
} 

しかし、それはこの同じ方法論(差分データセットを伴う完全なデータセット)に付着するが、全く異なるスキーマを持って入ってくる複数のファイルで、この特定のデータセットで200以上のフィールドが、あります。明らかに、私はむしろ、私はちょうど各データセットのプロパティごとの比較をハードコードする代わりにファイルを実行することができますポータブルなものを持っているだろう。

両方のオブジェクトのプロパティを反復してnull値でない値を更新する方法はありますか?

+0

これを行うには、PropertyInfoを使用してプロパティを取得することができます。 –

答えて

9

まず第一に、あなたは更新したいエンティティを選択するには、このようなものを使用する必要があります:

var widget  = db.Widgets.First(p => p.ID == 1); 
var widget_diff = db.Widgets_Changes.First(p => p.ID == 1); 

今、あなたは、単にすべてのフィールドを更新するためにリフレクションを使用することができます。

foreach(var fromProp in typepf(Widget).GetProperties()) 
{ 
    var toProp = typeof(Widget_Change).GetProperty(fromProp.Name); 
    var toValue = toProp.GetValue(widget_diff, null); 
    if (toValue != null) 
    { 
     fromProp.SetValue(widget, toValue, null); 
    } 
} 

この缶プロパティのリストを前面に作成することで、少しだけスピードアップできるので、一度リフレクションを使用する必要があります:

public static class WidgetUtil 
{ 
    public static readonly IEnumerable<Tuple<PropertyInfo, PropertyInfo>> PropertyMap; 

    static Util() 
    { 
     var b = BindingFlags.Public | BindingFlags.Instance; 
     PropertyMap = 
      (from f in typeof(Widget).GetProperties(b) 
      join t in typeof(WidgetChange).GetProperties(b) on f.Name equals t.Name 
      select Tuple.Create(f, t)) 
      .ToArray(); 
    } 
} 

... 

foreach(var propertyPair in WidgetUtil.PropertyMap) 
{ 
    var toValue = propertyPair.Item2.GetValue(widget_diff, null); 
    if (toValue != null) 
    { 
     propertyPair.Item1.SetValue(widget, toValue, null); 
    } 
} 
あなたはこのような多くのエンティティタイプを持っている場合は3210

、あなたも、一般的なユーティリティにこれを行うことを検討することをお勧めします:

public static class WidgetUtil<T1, T2> 
{ 
    public static readonly IEnumerable<Tuple<PropertyInfo, PropertyInfo>> PropertyMap; 

    static WidgetUtil() 
    { 
     var b = BindingFlags.Public | BindingFlags.Instance; 
     PropertyMap = 
      (from f in typeof(T1).GetProperties(b) 
      join t in typeof(T2).GetProperties(b) on f.Name equals t.Name 
      select Tuple.Create(f, t)) 
      .ToArray(); 
    } 
} 
+0

私の良さ。これは、私が望むことができるものよりずっと優れています。ありがとうございました! –

+0

@ ajax81助けてくれてうれしい、ハッピーコーディング:) –

+0

あなたは私の一日を作った! +1 –

4

あなたはこのためにリフレクションを使用する場合があります。各ウィジェット/差分のすべてのプロパティ/フィールドをループし、そのプロパティ/フィールドの値を取得し、その差がnullの場合は元の値を使用します。 pswgの答え@

using(var db = new MyEntityDatabase()) 
{ 
    var widget  = from p in db.Widgets select p where p.ID == 1; 
    var widget_diff = from p in db.Widgets_Changes select p where p.ID == 1; 

    var properties = typeof(MyWidgetType).GetProperties(BindingFlags.Public | BindingFlags.Instance); 
    foreach(var property in properties) 
    { 
     //widget.column = widget_diff.column ?? widget.colum; 
     property.SetValue(property.GetValue(widget_diff) ?? property.GetValue(widget), widget); 
    } 

    //You can do the same for fields here if the entity has any fields (probably not). 
} 
+0

まさに私が探していたもの。ありがとうございました! –

+0

'widget'と' widget_diff'の型が異なる場合、これは動作しません。オブジェクトごとに適切な 'PropertyInfo'を使う必要があります。 –

2

私はそれを実装しようとしたとき、私はあなたがobj.Equals(ヌル)にnullをチェックすることはできません例えばなど、いくつかのバグを(遭遇したが、素晴らしいですが、nullではありませんEqualsメソッドを持つ)。ここで

@のpswgの偉大な答えの「完全なコピー-pastable溶液」(副産物として)である

更新したいソースエンティティと宛先「sparceを取得InjectNonNull静的ジェネリックメソッド"エンティティはヌルを持ち、デスティネーションエンティティの非ヌルプロパティのみを転送します。

private static class PropertyLister<T1, T2> 
    { 
     public static readonly IEnumerable<Tuple<PropertyInfo, PropertyInfo>> PropertyMap; 

     static PropertyLister() 
     { 
      var b = BindingFlags.Public | BindingFlags.Instance; 
      PropertyMap = 
       (from f in typeof(T1).GetProperties(b) 
       join t in typeof(T2).GetProperties(b) on f.Name equals t.Name 
       select Tuple.Create(f, t)) 
        .ToArray(); 
     } 
    } 


    public static T InjectNonNull<T>(T dest, T src) 
    { 
     foreach (var propertyPair in PropertyLister<T, T>.PropertyMap) 
     { 
      var fromValue = propertyPair.Item2.GetValue(src, null); 
      if (fromValue != null && propertyPair.Item1.CanWrite) 
      { 

       propertyPair.Item1.SetValue(dest, fromValue, null); 
      } 
     } 

     return dest; 
    } 
+0

+1はい、私は実際にその問題を少し前に見ました。 'toValue.Equals(null)'は 'toValue!= null'または' Object.Equals(toValue、null) 'でなければなりません。私は完全性のために私の答えを修正しましたが、 'propertyPair.Item1.CanWrite'を追加することも良い考えです。 –

関連する問題