C# 在GroupJoin()之后选择many()

C# 在GroupJoin()之后选择many(),c#,linq,C#,Linq,基本上,我想做的是将两个表连接起来,并以一个简单的结果显示它们。为简单起见,我的两个表如下所示: tot["nameA", "nameB", "nameC"] critItg["nameA", "nameB"] leftName, rightName "nameA", "nameA" "nameB", "nameB" "nameC", empty/null { tot = { totName = "nameA" }, { critITG = "nameA"} } { tot = { totN

基本上,我想做的是将两个表连接起来,并以一个简单的结果显示它们。为简单起见,我的两个表如下所示:

tot["nameA", "nameB", "nameC"]
critItg["nameA", "nameB"]
leftName, rightName
"nameA", "nameA"
"nameB", "nameB"
"nameC", empty/null
{ tot = { totName = "nameA" }, { critITG = "nameA"} }
{ tot = { totName = "nameB" }, { critITG = "nameB"} }
{ tot = { totName = "nameC" }, { critITG = null} }
{ totName = "nameA", critITG = "nameA" }
我希望左外部联接后的结果如下所示:

tot["nameA", "nameB", "nameC"]
critItg["nameA", "nameB"]
leftName, rightName
"nameA", "nameA"
"nameB", "nameB"
"nameC", empty/null
{ tot = { totName = "nameA" }, { critITG = "nameA"} }
{ tot = { totName = "nameB" }, { critITG = "nameB"} }
{ tot = { totName = "nameC" }, { critITG = null} }
{ totName = "nameA", critITG = "nameA" }
我已通过以下方式成功执行左外连接:

var res = tot.GroupJoin
                (
                    critITG,
                    left => left.totName,
                    right => right.critITGName,
                    (left, right) => new
                    {
                        tot = left,
                        critITG = right.FirstOrDefault()
                    }
                );
但是,结果按如下方式分组:

tot["nameA", "nameB", "nameC"]
critItg["nameA", "nameB"]
leftName, rightName
"nameA", "nameA"
"nameB", "nameB"
"nameC", empty/null
{ tot = { totName = "nameA" }, { critITG = "nameA"} }
{ tot = { totName = "nameB" }, { critITG = "nameB"} }
{ tot = { totName = "nameC" }, { critITG = null} }
{ totName = "nameA", critITG = "nameA" }
我希望结果看起来更像这样:

tot["nameA", "nameB", "nameC"]
critItg["nameA", "nameB"]
leftName, rightName
"nameA", "nameA"
"nameB", "nameB"
"nameC", empty/null
{ tot = { totName = "nameA" }, { critITG = "nameA"} }
{ tot = { totName = "nameB" }, { critITG = "nameB"} }
{ tot = { totName = "nameC" }, { critITG = null} }
{ totName = "nameA", critITG = "nameA" }
我已经读到,展平左侧外部联接结果的解决方案是SelectMany(),但在上面的结果集中实现它时遇到了困难。以下结果集为“对象引用未设置为对象的实例”:

var res = tot.GroupJoin
                (
                    critITG,
                    left => left.totName,
                    right => right.critITGName,
                    (left, right) => new
                    {
                        tot = left,
                        critITG = right.FirstOrDefault()
                    }
                )
                .SelectMany
                (
                    right => right.critITG.critITGName.DefaultIfEmpty(),
                    (left, right) => 
                        new 
                        { 
                            leftName = left.tot.totName, 
                            rightName = right 
                        }
                );

感谢您的帮助!

您不需要在此处选择多个。您可以使用
选择
,但您只需在传递给
GroupJoin的代理中选择所需的数据即可:

var res = tot.GroupJoin
                (
                    critITG,
                    left => left.totName,
                    right => right.critITGName,
                    (left, right) => {
                        var mr = right.FirstOrDefault();
                        return new
                        {
                            totName = left.totName,
                            critITG = mr == null ? null : mr.critITGName
                        };
                    }
                );

您不需要在此处选择多个
。您可以使用选择,但您可以在传递给
GroupJoin
的委托中选择所需的数据:

var res = tot.GroupJoin
                (
                    critITG,
                    left => left.totName,
                    right => right.critITGName,
                    (left, right) => {
                        var mr = right.FirstOrDefault();
                        return new
                        {
                            totName = left.totName,
                            critITG = mr == null ? null : mr.critITGName
                        };
                    }
                );

看起来你已经陷入了lambda结构的技术细节中,这可能会导致代码的可维护性随着时间的推移而降低。我经常发现查询语法比LAMBDA语法更简单,更易于维护。

var tots = new string[] {"nameA", "nameB", "nameC"};
var critItgs = new string[] {"nameA", "nameB"};

var query = from tot in tots
      join critItg in critItgs on tot equals critItg into joined
      from row in joined.DefaultIfEmpty()
      select new {totName = tot, critItg = row};
query.Dump();

看起来你已经陷入了lambda结构的技术细节中,这可能会导致代码的可维护性随着时间的推移而降低。我经常发现查询语法比LAMBDA语法更简单,更易于维护。

var tots = new string[] {"nameA", "nameB", "nameC"};
var critItgs = new string[] {"nameA", "nameB"};

var query = from tot in tots
      join critItg in critItgs on tot equals critItg into joined
      from row in joined.DefaultIfEmpty()
      select new {totName = tot, critItg = row};
query.Dump();

不确定这是否是您需要的…但您是否尝试过为每个字段选择名称

var res = tot.GroupJoin
            (
                critITG,
                left => left.totName,
                right => right.critITGName,
                (left, right) => new
                {
                    tot = left.totName,
                    critITG = right.FirstOrDefault() == null ? null : right.critITGName
                }
            );
编辑: 我也同意@Jim Wooley,有时候不使用lambda表达式更容易。 请注意,您需要将您的totName和CrititName添加到他的代码中

  var res = from totElement in tot
  join critItgItem in critItgon totElement.Name equals critItgItem.Name into joined
  from row in joined.DefaultIfEmpty()
  select new {totName = tot.Name, critItg = (row == null ? String.Empty : row.Name) };

不确定这是否是您需要的…但您是否尝试过为每个字段选择名称

var res = tot.GroupJoin
            (
                critITG,
                left => left.totName,
                right => right.critITGName,
                (left, right) => new
                {
                    tot = left.totName,
                    critITG = right.FirstOrDefault() == null ? null : right.critITGName
                }
            );
编辑: 我也同意@Jim Wooley,有时候不使用lambda表达式更容易。 请注意,您需要将您的totName和CrititName添加到他的代码中

  var res = from totElement in tot
  join critItgItem in critItgon totElement.Name equals critItgItem.Name into joined
  from row in joined.DefaultIfEmpty()
  select new {totName = tot.Name, critItg = (row == null ? String.Empty : row.Name) };

Hi与Lee的示例类似,但有些不同,这里我在要返回的最终匿名类型中使用了select语句:

var res = tot.GroupJoin(critItg,
            left => left.Name,
            right => right.Name,
            (left, right) => new
            {
                tot = left.Name,
                critItg = right.Select(x => x.Name).FirstOrDefault()
            });

Hi与Lee的示例类似,但有些不同,这里我在要返回的最终匿名类型中使用了select语句:

var res = tot.GroupJoin(critItg,
            left => left.Name,
            right => right.Name,
            (left, right) => new
            {
                tot = left.Name,
                critItg = right.Select(x => x.Name).FirstOrDefault()
            });

谢谢。但是您的代码给了我一个错误:“mr:mr.critITGName“='无法确定条件表达式的类型,因为'AnonymousType#1'和'string'之间没有隐式转换任何想法?@Skalis-抱歉,如果右侧为null,则应为null,而不是
mr
。我已经更新了代码。@JimWooley-
left
right
不是字符串,否则
left=>left.totName
right=>right.critITGName
不会编译。@Lee,谢谢你的更正。我看到的是最初提议的集合,而不是最初的GroupJoin实现。谢谢。我想这样做,谢谢。但是,您的代码给了我一个错误:“mr:mr.critITGName”=”无法确定条件表达式的类型,因为在“匿名类型#1”和“字符串”之间没有隐式转换。有什么想法吗?@Skalis-对不起,如果右侧为null,则应该为null,而不是
mr
。我已经更新了代码。@JimWooley-
left
right
不是字符串,否则
left=>left.totName
right=>right.critITGName
不会编译。@Lee,谢谢你的更正。我看到的是最初提议的集合,而不是最初的GroupJoin实现。谢谢。我想要的工作方式。