4

EntityFrameworkでバックアップされたリポジトリに繰り返し発生するコードブロックがあり、何らかの方法で一般化してメソッドとして呼び出したいので、コードを繰り返すのではなく再利用します。

現在のコードブロックは次のようになります。

        // Archive deleted MyItems sections
        _t.MyItems.Where(x => x.ValidTo == null && !team.MyItems.Contains(x)).ToList().ForEach(x => x.ValidTo = DateTime.Now);

        // Add or update MyItems sections
        foreach (var MyItemsSection in team.MyItems)
        {
            if (MyItemsSection.Id == default(int))
            {
                MyItemsSection.ValidFrom = DateTime.Now;
                _t.MyItems.Add(MyItemsSection);
            }
            else
            {
                var _MyItemsSection = _t.MyItems.FirstOrDefault(x => x.Id == MyItemsSection.Id);
                context.Entry(_MyItemsSection).CurrentValues.SetValues(MyItemsSection);
            }
        }

_tはEntityFrameworkに接続されたオブジェクトグラフteamですが、は切断され、外部で更新された可能性のある同じタイプのオブジェクトグラフです。ここでの目標は、2つのオブジェクトグラフを同期して、変更が永続化されるようにすることです。

_t.MyItemsとteam.MyItemsを渡す必要があります。ここで、MyItemsはジェネリック化されるため、同じメソッドがMyOtherItemsとMySocks、MyUnderPantsなどで機能します。

これは可能ですか?

4

2 に答える 2

1

2つの選択肢があります。汎用メソッドでアクセスするプロパティとメソッドを含む既知の基本タイプにオブジェクトを制約するか、述語を使用して選択を行います。

制約:

// base type
interface IFoo {
  int ID { get; set; }
}

  // generic method
  public List<T> Update<T>(List<T> graph1, List<T> graph2) where T : IFoo {
    var update = graph1.Intersect(graph2, (g1, g2) => { g1.ID == g2.ID }).ToList();
    return update;
  }

述語:

public void Update<T, U>(T _t, T team, Func<T, IList<U>> selector) 
{
    var _tItems = selector(_t);
    var teamItems = selector(team);

    // Archive deleted MyItems sections
    _tItems.Where(x => x.ValidTo == null && !teamItems.Contains(x)).ToList().ForEach(x => x.ValidTo = DateTime.Now);

    // Add or update MyItems sections
    foreach (var MyItemsSection in teamItems)
    {
        if (MyItemsSection.Id == default(int))
        {
            MyItemsSection.ValidFrom = DateTime.Now;
            _tItems.Add(MyItemsSection);
        }
        else
        {
            var _MyItemsSection = _tItems.FirstOrDefault(x => x.Id == MyItemsSection.Id);
            context.Entry(_MyItemsSection).CurrentValues.SetValues(MyItemsSection);
        }
    }
}

    //Usage:
    Update(_t, team, (t => t.MyItems));

しかし、繰り返しになりますが、リストをパラメーターとして受け取るメソッドを作成することを妨げるものは何ですか?

のようにpublic void Update<T>(IList<T> _tItems, IList<T> teamItems)

于 2012-11-23T15:59:15.077 に答える
1

私自身の質問への答えとして、ここに答えがあります-私が見逃していたのは、特定のインターフェイスを実装するものとして着信型を要求し、それでも必要な型として使用できるという事実でした。

だから、これが私が思いついたものです:

public void UpdateEntities<TEntity>(ICollection<TEntity> pocoCollection, ICollection<TEntity> dbCollection)
        where TEntity : class, IEntity
    {
        // Archive deleted entities
        dbCollection.Where(x => x.ValidTo == null && !pocoCollection.Contains(x)).ToList().ForEach(x => x.ValidTo = DateTime.Now);

        // Add or update entities
        foreach (var entity in pocoCollection)
        {
            if (entity.Id == default(int))
            {
                entity.ValidFrom = DateTime.Now;
                dbCollection.Add(entity);
            }
            else
            {
                var _entity = dbCollection.FirstOrDefault(x => x.Id == entity.Id);
                context.Entry(_entity).CurrentValues.SetValues(entity);
            }
        }
    }

私が探していたのはwhere TEntity : class, IEntity

このソリューションでは、エンティティがインターフェイスIEntityを実装していることを確認する必要があります。これは単純に次のとおりです。

public interface IEntity
{
    int Id { get; set;}
    DateTime ValidFrom { get; set; }
    DateTime? ValidTo { get; set; }
}

これにより、コンパイラはこれらのプロパティの使用について不平を言うのをやめることができますが、実際の型を使用できるので、Entity Frameworkも満足し、何が起こっているのかについて混乱することが少なくなります。

これが他の誰かに役立つことを願っています。

于 2012-11-27T13:54:22.923 に答える