接上一篇,我们发现两表连接方式默认为内连接,而我们在SQL中常用到的左连接没有封装方法。换句话说,微软放弃两表左连或右连的这种做法(只有在2个表都存在值时,这样的连接才有意义)。

如果要实现表的左连接,就不能调用他现有的封装方法了,可以用LINQ来实现。

var joinTable = (from left in table1.AsEnumerable()
join right in table2.AsEnumerable()
on left["ID"].ToString() equals right["ID"].ToString() into newTable
from right in newTable.DefaultIfEmpty()
select new
{
LeftID = left["ID"].ToString(),
RightID = right != null ? right["ID"].ToString() : default(string),
LeftName = left["Name"].ToString(),
RightName = right != null ? right["Name"].ToString() : default(string)
}).ToList();
joinTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}\t{3}", t.LeftID, t.RightID, t.LeftName, t.RightName));

功能是实现了,但是这样又要憋死一群强迫症患者,非要用Join封装方法来实现这个功能。

那我们就来手动封装一个左连接方法吧。

public static IEnumerable<Result> LeftJoin<TOuter, TInner, TKey, Result>(
this IEnumerable<TOuter> outer
, IEnumerable<TInner> inner
, Func<TOuter, TKey> outerKeySelector
, Func<TInner, TKey> innerKeySelector
, Func<TOuter, TInner, Result> resultSelector
, IEqualityComparer<TKey> comparer)
{
if (outer == null)
throw new ArgumentException("outer"); if (inner == null)
throw new ArgumentException("inner"); if (outerKeySelector == null)
throw new ArgumentException("outerKeySelector"); if (innerKeySelector == null)
throw new ArgumentException("innerKeySelector"); if (resultSelector == null)
throw new ArgumentException("resultSelector"); return LeftJoinImpl(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer ?? EqualityComparer<TKey>.Default);
} static IEnumerable<Result> LeftJoinImpl<TOuter, TInner, TKey, Result>(
IEnumerable<TOuter> outer, IEnumerable<TInner> inner
, Func<TOuter, TKey> outerKeySelector
, Func<TInner, TKey> innerKeySelector
, Func<TOuter, TInner, Result> resultSelector
, IEqualityComparer<TKey> comparer)
{
var innerLookup = inner.ToLookup(innerKeySelector, comparer); foreach (var outerElment in outer)
{
var outerKey = outerKeySelector(outerElment);
var innerElements = innerLookup[outerKey]; if (innerElements.Any())
foreach (var innerElement in innerElements)
yield return resultSelector(outerElment, innerElement);
else
yield return resultSelector(outerElment, default(TInner));
}
}

PS:以上这段代码转载自stackoverflow.com

var joinTable = table1.AsEnumerable().LeftJoin(table2.AsEnumerable(),
left => left["ID"].ToString(),
right => right["ID"].ToString(),
(left, right) => new
{
LeftID = left["ID"].ToString(),
RightID = right != null ? right["ID"].ToString() : default(string),
LeftName = left["Name"].ToString(),
RightName = right != null ? right["Name"].ToString() : default(string)
}, null).ToList();
joinTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}\t{3}", t.LeftID, t.RightID, t.LeftName, t.RightName));

是不是和之前的Join方法一样,这样用起来很方便了吧。

IEnumerable的一些基本方法 补充的更多相关文章

  1. C# 索引器,实现IEnumerable接口的GetEnumerator()方法

    当自定义类需要实现索引时,可以在类中实现索引器. 用Table作为例子,Table由多个Row组成,Row由多个Cell组成, 我们需要实现自定义的table[0],row[0] 索引器定义格式为 [ ...

  2. 为IEnumerable扩展一个ForEach方法

    IEnumerable没有一个ForEach方法,我们可以使用C#写一个扩展方法: Source Code: using System; using System.Collections.Generi ...

  3. IEnumerable接口的扩展方法

    /// <summary>/// IEnumerable接口的扩展方法,支持它的实现类是List的情况/// </summary>using System.Collection ...

  4. python 魔法方法补充(__setattr__,__getattr__,__getattribute__)

    python 魔法方法补充 1 getattribute (print(ob.name) -- obj.func())当访问对象的属性或者是方法的时候触发 class F(object): def _ ...

  5. python基础知识五 各类型数据方法补充,转换,分类,编码+坑中菜

    3.9各类型数据方法补充,转换,分类,编码,坑中菜 3.9.1数据类型方法补充 1.str:不可变 补充方法 s1.capitalize():首字母大写 s1 = "alex" s ...

  6. C#对IQueryable<T>、IEnumerable<T>的扩展方法

    #region IQueryable<T>的扩展方法 #region 根据第三方条件是否为真是否执行指定条件的查询 /// <summary> /// 根据第三方条件是否为真是 ...

  7. 像画笔一样慢慢画出Path的三种方法(补充第四种)

    今天大家在群里大家非常热闹的讨论像画笔一样慢慢画出Path的这种效果该如何实现. 北京-LGL 博客号@ligl007发起了这个话题.然后各路高手踊跃发表意见.最后雷叔 上海-雷蒙 博客号@雷蒙之星 ...

  8. IEnumerable接口的Aggregate方法

    以前小猪为了累加一个集合中的类容通常会写出类似这样的C#代码: string result ="": foreach (var item in items) { result+=i ...

  9. IEnumerable中的 Any方法

    IEnumerable类中的 Any方法,表示集合中有任何一元素满足条件,返回就true , 该方法有两个重载 1. 不带任何参数,表示集合中有元素 2. 参入一个 Func<TSource, ...

随机推荐

  1. Openstack(Kilo)安装系列之环境准备(二)

    控制节点.网络节点.计算节点: 一.配置源 1.配置EPEL源 yum install http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-rel ...

  2. CI的意思

    Continuous integration (CI) is the practice, in software engineering, of merging all developer worki ...

  3. NetCore 中 EFcore的DbFirst和CodeFirst混合 使用注意

    NetCore 最近很火热.笔者想把自己以前的旧项目迁移到NetCore平台. 先用EFcore的DBFirst根据数据库创建实体类,然后加入数据库版本控制功能也就是EFcore的CodeFirst部 ...

  4. asp.net c#采集需要登录页面的实现原理及代码

    当我们采集页面的时候,如果被采集的网站需要登录才能采集,原理搞清楚了,就好办了,我们所要做的仅仅是在采集的时候(或者说HttpWebRequest提交数据的时候),将Cookie信息放入Http请求头 ...

  5. Android无线测试之—Genymotion配置过程中常见问题

    一.前提条件: 已经部署好了Android UiAutomator测试环境. 二.在部署Genymotion时遇到了两类问题: 1.通过eclipse打开一个模拟设备,然后将编译好的jar包push到 ...

  6. Android开发:《Gradle Recipes for Android》阅读笔记1.7——仓库配置

    repositories块告诉gradle哪里去寻找依赖,默认的android studio使用jcenter或者mavenCentral.jcenter仓库位于https://jcenter.bin ...

  7. java用iText导出word文档

    1.需要导入的jar包 2.导出word并下载其实是分两步的. 第一步是将需要导出的数据导出(上传)到服务器上 第二步是将服务器上的文档下载到本地 3. 第一步.上传文档 (1)设置响应信息以及构造上 ...

  8. JS探秘——那些你理解存在偏差的问题

    Javascript的连续赋值运算 var a = {n:1}; a.x = a = {n:2}; alert(a.x); // --> undefined 看 jQuery 源码 时发现的这种 ...

  9. 《从零开始学Swift》学习笔记(Day 30)——选择类还是结构体呢?

    原创文章,欢迎转载.转载请注明:关东升的博客 类和结构体非常相似,很多情况下没有区别.如果你是设计人员在进行系统设计时候,是将某种类型设计成为类还是结构体? 类和结构体异同: 类和结构体都有如下功能: ...

  10. js判断选择的时间是否大于今天

    获取的时间格式为  2012-5-28var thetime = document.getElementById("clearDate").value;var   d=new   ...