应无所住,而生其心
排名
6
文章
6
粉丝
16
评论
8
{{item.articleTitle}}
{{item.blogName}} : {{item.content}}
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2024TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

集合查询的SelectMany原理

5127人阅读 2018/10/11 17:21 总访问:4814356 评论:0 收藏:0 手机
分类: EF


自己写一下里边的原理对了解它的用法有很大的帮助,select都作用类似就是把1对多的格式处理成1对1的格式,

比如这里的把UserScoreViewModel格式处理成UserScoreViewModel2

我们要想写通用的扩展方法出来可以先写一个专门的处理UserScoreViewModel格式成UserScoreViewModel2的方法,这样做也便于我们分析和理解问题,特别是如果我们要进行授课,这种方式更能够让人理解,一步一步的深入。

其实很简单就是两个遍历就好

/// <summary>
/// 把List<UserScoreViewModel>转换成List<UserScoreViewModel2>格式
/// </summary>
public List<UserScoreViewModel2> Parse(List<UserScoreViewModel> source)
{
    List<UserScoreViewModel2> result = new List<UserScoreViewModel2>();
    foreach (UserScoreViewModel item in source)
    {
        foreach (Score scoreItem in item.scoreList)
        {
            UserScoreViewModel2 uscore = new UserScoreViewModel2();
            uscore.UserName = item.UserName;
            uscore.score = scoreItem;
            result.Add(uscore);
        }
    }
    return result;
}

如果要处理一下为空的情况,我们加一个为空验证即可

//解析成1对1的集合
List<UserScoreViewModel2> userScoreViewModel2List = new List<UserScoreViewModel2>();
foreach (UserScoreViewModel item in userScoreList)
{
    foreach (Score score in item.scores.DefaultIfEmpty())
    {
        UserScoreViewModel2 userScoreViewModel2 = new UserScoreViewModel2();
        userScoreViewModel2.Id = item.Id;
        userScoreViewModel2.UserName = item.UserName;
        userScoreViewModel2.Number = item.Number;

        if (score != null)
        {
            userScoreViewModel2.Sub = score.Sub;
            userScoreViewModel2.score = score.Score1;
        }
        userScoreViewModel2List.Add(userScoreViewModel2);
    }
}

然后我们在去写通用的:

public static class IEnumberExtands
{
    /// <summary>
    /// 自己实现MySelectMany
    /// </summary>
    /// <typeparam name="TSource">对应外面的集合源类型</typeparam>
    /// <typeparam name="TCollection">集合里边子集合类型</typeparam>
    /// <typeparam name="TResult">返回值类型</typeparam>
    /// <returns></returns>
    public static IEnumerable<TResult> MySelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
    {
        List<TResult> resultList = new List<TResult>();
        foreach (TSource tsource in source)
        {
            //通过外面传递的lamdba拿到集合
            IEnumerable<TCollection> sublist = collectionSelector(tsource);
            foreach (TCollection item in sublist)
            {
                //通过外面传递的lamdba拿到返回对象
                TResult result = resultSelector(tsource, item);
                resultList.Add(result);
            }
        }
        return resultList;
    }
}

上面的方法没有处理为空的情况,如果外面写了DefaultIfEmpty()就容易报错,我们可以选择在外面去处理:

List<UserScoreViewModel2> userScoreList = oaEntities.UserInfo.GroupJoin(oaEntities.Score, a => a.Id, b => b.UserId, (user, score) => new UserScoreViewModel
{
    Id = user.Id,
    UserName = user.UserName,
    Number = user.Number,
    scores = score
}).ToList().SelectMany(a => a.scores.DefaultIfEmpty(), (a, b) =>
{
    UserScoreViewModel2 ss = new UserScoreViewModel2
        {
            Id = a.Id,
            UserName = a.UserName,
            Number = a.Number
        };
    //为空处理
    if (b != null)
    {
        ss.Sub = b.Sub;
        ss.score = b.Score1;
    }

    return ss;
}).ToList();

当然上面哪种方式有点麻烦,我们可以在扩展方法中去处理。我们可以使用反射创建一个默认对象处理一下这种情况,不然我们就只有在外面去处理了

public static IEnumerable<TResult> MySelectMany<TSource, TCollection, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
{
    List<TResult> userScoreViewModel2List = new List<TResult>();
    foreach (TSource item in source)
    {
        foreach (TCollection score in collectionSelector(item))
        {
            if (score == null)
            {
                //使用反射创建对象,避免为空报错,为空的时候我们就给一个默认值
                TCollection collobj = Activator.CreateInstance<TCollection>();
                TResult tresult = resultSelector(item, collobj);
                userScoreViewModel2List.Add(tresult);
            }
            else
            {
                TResult tresult = resultSelector(item, score);
                userScoreViewModel2List.Add(tresult);
            }
        }
    }
    return userScoreViewModel2List;
}



欢迎加群讨论技术,群:677373950(满了,可以加,但通过不了),2群:656732739

评价