提供基于通用类型集合的通用键比较
Providing a generic key comparison based on a collection of a generic type
我已经为如下几种类型创建了自己的 InsertOrUpdate()
实现:
public IEnumerable<Genre> InsertOrUpdate(IEnumerable<Genre> genres)
{
foreach (var genre in genres)
{
var existingGenre = _context.Genres.SingleOrDefault(x => x.TmdbId == genre.TmdbId);
if (existingGenre != null)
{
existingGenre.Update(genre);
yield return existingGenre;
}
else
{
_context.Genres.Add(genre);
yield return genre;
}
}
_context.SaveChanges();
}
IEnumerable<T>
的 return 类型是必需的,因为它将用于在数据上下文中插入根对象。此方法基本上检索附加对象(如果存在)并使用最新值更新它(如果存在)或将其作为新对象插入(如果不存在)。之后,这个附加对象被 returned,因此它可以链接到多对多表中的根对象。
现在的问题是我有几个这样的集合(流派、海报、关键字等),每种类型的 ID 设置不同:有时称为 TmdbId
,有时称为 Id
,有时称为Iso
。使用一个接口,把它们都重命名为Id
是一回事,但问题是它们也是不同的类型:有的是int
,有的是string
.
问题很简单:我如何将它变成更通用的东西来避免代码重复?
到目前为止我一直在玩弄
public IEnumerable<T> InsertOrUpdate<T>(IEnumerable<T> entities, Func<T, bool> idExpression) where T : class
{
foreach (var entity in entities)
{
var existingEntity = _context.Set<T>().SingleOrDefault(idExpression);
if (existingEntity != null)
{
_context.Entry(existingEntity).CurrentValues.SetValues(entity);
yield return existingEntity;
}
else
{
_context.Set<T>().Add(entity);
yield return entity;
}
}
_context.SaveChanges();
}
但显然这行不通,因为我无权访问内部 entity
变量。旁注:IDbSet<T>().AddOrUpdate()
does not work in my scenario.
你可以试试:
public IEnumerable<T> InsertOrUpdate<T>(IEnumerable<T> entities, Func<T, object[]> idExpression) where T : class
和
var existingEntity = _context.Set<T>().Find(idExpression(entity));
调用
movie.Genres = new List<Genre>(InsertOrUpdate(movie.Genres, x => new object[] { x.Id }));
(注意returns一个IEnumerable<>
的方法非常危险...如果你不列举它,比如
InsertOrUpdate(movie.Genres, x => x.Id);
那么该方法将不会完全执行,因为它会被延迟执行"on demand")
如果只有单键表,可以改成:
public IEnumerable<T> InsertOrUpdate<T>(IEnumerable<T> entities, Func<T, object> idExpression) where T : class
和
var existingEntity = _context.Set<T>().Find(new object[] { idExpression(entity) });
和
movie.Genres = new List<Genre>(InsertOrUpdate(movie.Genres, x => x.Id));
我已经为如下几种类型创建了自己的 InsertOrUpdate()
实现:
public IEnumerable<Genre> InsertOrUpdate(IEnumerable<Genre> genres)
{
foreach (var genre in genres)
{
var existingGenre = _context.Genres.SingleOrDefault(x => x.TmdbId == genre.TmdbId);
if (existingGenre != null)
{
existingGenre.Update(genre);
yield return existingGenre;
}
else
{
_context.Genres.Add(genre);
yield return genre;
}
}
_context.SaveChanges();
}
IEnumerable<T>
的 return 类型是必需的,因为它将用于在数据上下文中插入根对象。此方法基本上检索附加对象(如果存在)并使用最新值更新它(如果存在)或将其作为新对象插入(如果不存在)。之后,这个附加对象被 returned,因此它可以链接到多对多表中的根对象。
现在的问题是我有几个这样的集合(流派、海报、关键字等),每种类型的 ID 设置不同:有时称为 TmdbId
,有时称为 Id
,有时称为Iso
。使用一个接口,把它们都重命名为Id
是一回事,但问题是它们也是不同的类型:有的是int
,有的是string
.
问题很简单:我如何将它变成更通用的东西来避免代码重复?
到目前为止我一直在玩弄
public IEnumerable<T> InsertOrUpdate<T>(IEnumerable<T> entities, Func<T, bool> idExpression) where T : class
{
foreach (var entity in entities)
{
var existingEntity = _context.Set<T>().SingleOrDefault(idExpression);
if (existingEntity != null)
{
_context.Entry(existingEntity).CurrentValues.SetValues(entity);
yield return existingEntity;
}
else
{
_context.Set<T>().Add(entity);
yield return entity;
}
}
_context.SaveChanges();
}
但显然这行不通,因为我无权访问内部 entity
变量。旁注:IDbSet<T>().AddOrUpdate()
does not work in my scenario.
你可以试试:
public IEnumerable<T> InsertOrUpdate<T>(IEnumerable<T> entities, Func<T, object[]> idExpression) where T : class
和
var existingEntity = _context.Set<T>().Find(idExpression(entity));
调用
movie.Genres = new List<Genre>(InsertOrUpdate(movie.Genres, x => new object[] { x.Id }));
(注意returns一个IEnumerable<>
的方法非常危险...如果你不列举它,比如
InsertOrUpdate(movie.Genres, x => x.Id);
那么该方法将不会完全执行,因为它会被延迟执行"on demand")
如果只有单键表,可以改成:
public IEnumerable<T> InsertOrUpdate<T>(IEnumerable<T> entities, Func<T, object> idExpression) where T : class
和
var existingEntity = _context.Set<T>().Find(new object[] { idExpression(entity) });
和
movie.Genres = new List<Genre>(InsertOrUpdate(movie.Genres, x => x.Id));