根据通用类型的集合提供通用密钥比较 [英] Providing a generic key comparison based on a collection of a generic type

查看:106
本文介绍了根据通用类型的集合提供通用密钥比较的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为以下几种类型创建了自己的InsertOrUpdate()实现:

I have created my own InsertOrUpdate() implementations for a few types like this:

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>是必需的,因为它将用于在数据上下文中插入根对象.此方法基本上会检索附加对象(如果存在),如果存在则使用最新值对其进行更新,如果不存在,则将其作为新对象插入.然后,返回此附加对象,以便可以将其链接到多对多表中的根对象.

The return type of IEnumerable<T> is required because it will be used to insert the root object in the datacontext. This method basically retrieves the attached object if it exists and updates it with the newest values if it does or inserts it as a new object if it doesn't. Afterwards this attached object is returned so it can be linked to the root object in the many-to-many tables.

现在的问题是,我有几个这样的集合(类型,海报,关键字等),每种类型的ID设置不同:有时称为TmdbId,有时称为Id,有时称为Iso.使用接口并将它们全部重命名为Id是一回事,但是存在的问题是它们也是不同的类型:有些是int,有些是string.

The problem now is that I have several of these collections (genres, posters, keywords, etc) and each type's ID is differently setup: sometimes it's called TmdbId, sometimes Id and sometimes Iso. It's one thing to use an interface and rename them all to Id but the problem exists in that they are also different types: some are int and some are string.

问题很简单:我如何将其转换为更通用的名称,以避免代码重复?

The question is easy: how I do turn this into something more generic to avoid this code duplication?

到目前为止,我一直在玩弄

So far I have been toying around with

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() 在我的情况下不起作用.

but obviously this won't work since I have no access to the inner entity variable. Sidenote: 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 }));

(请注意,返回IEnumerable<>的方法非常危险非常 ...如果您不枚举它,例如

(note that a method that returns a IEnumerable<> is very dangerous... If you don't enumerate it, like

InsertOrUpdate(movie.Genres, x => x.Id);

然后该方法将不会完全执行,因为它会按需"延迟执行)

then the method won't be executed fully, because it will be lazily executed "on demand")

如果只有单键表,则可以将其更改为:

If you only have single-key tables, you can change it to:

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));

这篇关于根据通用类型的集合提供通用密钥比较的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆