关于c#:如何在单个连接中的多个字段上进行LINQ连接

How to do joins in LINQ on multiple fields in single join

我需要执行一个linq2dataset查询,该查询在多个字段上执行join(as

1
2
3
4
5
var result = from x in entity
join y in entity2
       on x.field1 = y.field1
and
          x.field2 = y.field2

我已经找到了一个合适的解决方案(我可以向WHERE子句添加额外的约束,但这远远不是一个合适的解决方案,或者使用这个解决方案,但它假定一个等价连接)。

在LINQ中,可以在一个联接中联接多个字段吗?

编辑

1
2
3
var result = from x in entity
             join y in entity2
             on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

是我在上面假设的一个等式中引用的解决方案。

进一步编辑

为了回答我最初的例子是equijoin的批评,我承认,我目前的要求是equijoin,我已经采用了我上面提到的解决方案。

不过,我正在努力了解我在LINQ中有/应该采用哪些可能性和最佳实践。我很快将需要使用表ID进行日期范围查询联接,并且只是抢先解决了这个问题,看起来我必须在WHERE子句中添加日期范围。

一如既往地感谢您提出的所有建议和意见


1
2
var result = from x in entity
   join y in entity2 on new { x.field1, x.field2 } equals new { y.field1, y.field2 }


匿名类型的解决方案应该可以正常工作。Linq只能表示equijoin(无论如何都有join子句),实际上,这就是您所说的,您无论如何都希望基于原始查询来表示的内容。

如果出于某种特定的原因,您不喜欢匿名类型的版本,那么应该解释这个原因。

如果你想做你最初要求以外的事情,请举一个你真正想做的例子。

编辑:回答问题中的编辑:是的,要进行"日期范围"联接,您需要改用WHERE子句。它们在语义上是等价的,所以这只是可用的优化问题。Equijoin通过创建基于内部序列的查找来提供简单的优化(在对象的LINQ中,其中包括LINQ到数据集),将其视为从键到匹配该键的一系列条目之间的哈希表。

使用日期范围执行此操作有些困难。但是,根据"日期范围联接"的确切含义,您可能可以执行类似的操作-如果您计划创建日期的"带区"(例如每年一个),以便同一年(但不是同一日期)中发生的两个条目匹配,那么您可以仅使用该带作为键来执行此操作。如果更复杂,例如连接的一边提供了一个范围,而连接的另一边提供了一个单一的日期,如果它在这个范围内匹配,那么在imo中使用where子句(在第二个from子句之后)可以更好地处理它。您可以通过命令一边或另一边查找来做一些特别有趣的魔术。匹配效率更高,但这将是很多工作-我只会在检查性能是否是一个问题之后做那种事情。


1
2
3
var result = from x in entity1
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }

如果两个实体中的列名不同,则需要执行此操作。


只需使用等效方法链语法完成此操作:

1
2
entity.Join(entity2, x => new {x.Field1, x.Field2},
                     y => new {y.Field1, y.Field2}, (x, y) => x);

最后一个参数(x, y) => x是您选择的(在上面的例子中,我们选择x)。


我认为更具可读性和灵活性的选择是使用where函数:

1
2
3
var result = from x in entity1
             from y in entity2
                 .Where(y => y.field1 == x.field1 && y.field2 == x.field2)

这还允许通过附加.defaultifempty()轻松地从内部联接更改为左联接。


1
2
3
4
5
6
7
var result = from x in entity
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }
             select new
             {
               /// Columns
              };


你可以做一些类似的事情(如下)

1
2
3
4
5
6
7
8
9
10
11
12
13
var query = from p in context.T1

        join q in context.T2

        on

        new { p.Col1, p.Col2 }

        equals

         new { q.Col1, q.Col2 }

        select new {p...., q......};


使用join运算符只能执行equijoin。可以使用其他运算符构造其他类型的联接。我不确定使用这些方法或通过更改WHERE子句,您尝试执行的确切联接是否更容易。关于join子句的文档可以在这里找到。msdn有一篇关于连接操作的文章,文章中还提供了指向其他连接示例的多个链接。


作为一个完整的方法链,如下所示:

1
2
3
4
5
6
7
lista.SelectMany(a => listb.Where(xi => b.Id == a.Id && b.Total != a.Total),
                (a, b) => new ResultItem
                {
                    Id = a.Id,
                    ATotal = a.Total,
                    BTotal = b.Total
                }).ToList();

如果实体中的字段名不同

1
2
3
4
5
6
7
8
9
10
11
12
var result = from x in entity
   join y in entity2 on
          new {
                field1=   x.field1,
               field2 =  x.field2
             }
          equals
         new {
                field1= y.field1,
                field2=  y.myfield
              }
select new {x,y});


声明一个类(类型)以保存要联接的元素。在下面的示例中,声明joinElement

1
2
3
4
5
6
7
8
9
10
11
 public class **JoinElement**
{
    public int? Id { get; set; }
    public string Name { get; set; }

}

results = from course in courseQueryable.AsQueryable()
                  join agency in agencyQueryable.AsQueryable()
                   on new **JoinElement**() { Id = course.CourseAgencyId, Name = course.CourseDeveloper }
                   equals new **JoinElement**() { Id = agency.CourseAgencyId, Name ="D" } into temp1


1
2
3
4
from d in db.CourseDispatches
                             join du in db.DispatchUsers on d.id equals du.dispatch_id
                             join u in db.Users on du.user_id equals u.id
                             join fr in db.Forumreports on (d.course_id + '_' + du.user_id)  equals  (fr.course_id + '_'+ fr.uid)

这对我有用