我在我的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等。
这一切都可能吗?
答案 0 :(得分: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)
答案 1 :(得分: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; }
}
这允许编译器退出抱怨使用这些属性,而我仍然可以使用实际类型,因此实体框架也很满意,并且不会对最近发生的事情感到困惑。
希望这有助于其他人。