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是已断开连接并可能在外部更新的相同类型的对象图。这里的目标是同步两个对象图,以便保持更改。

我需要传入 _t.MyItems 和 team.MyItems,其中 MyItems 将被泛化,因此相同的方法适用于 MyOtherItems 和 MySocks、MyUnderPants 等。

这是可能吗?

4

2 回答 2

1

您有两个选择:要么将对象限制为包含要在泛型方法中访问的属性和方法的已知基本类型,要么使用谓词进行选择。

约束:

// 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 回答