我可以使用 linq 将表加入列表吗? [复制]

Posted

技术标签:

【中文标题】我可以使用 linq 将表加入列表吗? [复制]【英文标题】:Can I join a table to a list using linq? [duplicate] 【发布时间】:2013-12-10 14:13:17 【问题描述】:

我有一张如下表:

PersonalDetails

Columns are:

Name  
BankName
BranchName
AccountNo
Address

我有另一个包含“姓名”和“帐号”的列表。 我必须从给定列表中找到相应“名称”和“帐户编号”的表中的所有记录。

任何建议都会有所帮助。

我做了以下但没有多大用处:

var duplicationhecklist = dataAccessdup.MST_FarmerProfile
                          .Join(lstFarmerProfiles, 
                                t => new  t.Name,t.AccountNo, 
                                t1 => new  t1.Name, t1.AccountNo, 
                                (t, t1) => new  t, t1 )
                           .Select(x => new 
                                               x.t1.Name,
                                               x.t1.BankName,
                                               x.t1.BranchName,
                                               x.t1.AccountNo
                                             ).ToList();

lstFarmerProfiles 是一个列表。

【问题讨论】:

您先向我们展示您的尝试如何? @gleng:现在你能帮忙吗? AccountNo 是否唯一标识记录? 我会考虑使用表值参数并为此编写自定义 SQL 查询...如果您有兴趣,我可以提供更多信息,但它并没有真正使用 linq,所以不确实是您具体问题的答案。 【参考方案1】:

您可能发现无法将实体框架 LINQ 查询与实体对象的本地列表连接起来,因为它无法转换为 SQL。我只会预先选择帐号上的数据库数据,然后加入内存。

var accountNumbers = lstFarmerProfiles.Select(x => x.AccountNo).ToArray();

var duplicationChecklist = 
        from profile in dataAccessdup.MST_FarmerProfile
                                     .Where(p => accountNumbers
                                                    .Contains(p.AccountNo))
                                     .AsEnumerable() // Continue in memory
        join param in lstFarmerProfiles on 
            new  profile.Name, profile.AccountNo equals 
            new  param.Name, param.AccountNo
        select profile

因此,您永远不会将批量数据拉入内存,而是您可能会继续进行的最小选择。

如果accountNumbers 包含数千个项目,您可以考虑使用可扩展性更好的chunky Contains method。

【讨论】:

我提供了更多细节here。 只是一个理论问题,但是为什么不能将本地列表翻译成SQL呢?当查询实际运行时,LINQ 应该能够使用本地列表中的数据创建一个临时表或表变量,然后加入其中。这是一个绝对应该包含在框架中的功能。 @jtate 在那个方向有一些private efforts。对我来说,这些只是表明这并不是微不足道的。 @GertArnold 这正是我的想象。对于相当小的内存集合,我认为这会很好。【参考方案2】:

由于您在 .net 中有要查找的值的列表,请尝试使用 Contains 方法作为示例:

List<string> names = /* list of names */;
List<string> accounts = /* list of account */;

var result = db.PersonalDetails.Where(x => names.Contains(x.Name) && accounts.Contains(x.AccountNo))
                               .ToList();

【讨论】:

只有一个包含姓名和帐户的列表。 它不会将数据库的每条记录与列表的每一行完全匹配。【参考方案3】:

如果MST_FarmerProfile 不是超级大,我认为您最好的选择是使用AsEnumerable() 将其放入内存并在那里加入。

var duplicationhecklist = 
             (from x in dataAccessdup.MST_FarmerProfile
                        .Select(z => new 
                                            z.Name, 
                                            z.BankName, 
                                            z.BranchName,
                                            z.AccountNo
                                          ).AsEnumerable()
              join y in lstFarmerProfiles
                 on new  x.Name, x.AccountNo equals new  y.Name, y.AccountNo
              select x).ToList();

【讨论】:

MST_FarmerProfile 包含 200 万条记录。你还会提出同样的建议吗? @sake 也许您不需要将表中的所有列都放入内存,在.AsEnumerable() 之前进行选择以获取您需要的列。了解执行时间是否可接受的唯一方法是对其进行测试。 @Saket lstFarmerProfiles 会有多大? lstFarmerProfiles 将包含 1000 条记录。 @Saket 告诉我进展如何。【参考方案4】:

由于数据通常位于不同的机器上或至少位于不同的进程中:DB - 是一个,而您的内存列表是您的应用程序,因此只有两种方法可以做到这一点。

    将尽可能小的数据部分从数据库下载到本地并在本地加入(通常使用AsEnumerable() 或基本上使用ToList())。您在其他答案中对此有很多好的想法。 另一个不同 - 以某种方式将本地数据上传到服务器并在数据库端执行查询。上传可以以不同的方式完成:使用一些临时表或使用 VALUES。幸运的是,您现在可以尝试 EF 的一个小扩展(适用于 EF6 和 EF Core)。它是 EntityFrameworkCore.MemoryJoin(名称可能令人困惑,但它同时支持 EF6 和 EF Core)。正如作者article 中所述,它修改了传递给服务器的 SQL 查询,并使用本地列表中的数据注入 VALUES 构造。并在数据库服务器上执行查询。

【讨论】:

我们刚刚添加了这个库,它太棒了!!!!这解决了 linq to entity 阻止您的大多数情况。 (我们一直在努力提供 ID 和保持排序顺序)【参考方案5】:

如果 accountNo 标识了记录,那么您可以使用:

var duplicationCheck = from farmerProfile in dataAccessdup.MST_FarmerProfile
                       join farmerFromList in lstFarmerProfiles
                       on farmerProfile.AccountNo equals farmerFromList.AccountNo
                       select new  
                                      farmerProfile.Name, 
                                      farmerProfile.BankName, 
                                      farmerProfile.BranchName, 
                                      farmerProfile.AccountNo 
                                  ;

如果您需要加入姓名和帐户,那么这应该可以:

 var duplicationCheck = from farmerProfile in dataAccessdup.MST_FarmerProfile
                        join farmerFromList in lstFarmerProfiles
                        on new
                        
                            accountNo = farmerProfile.AccountNo,
                            name = farmerProfile.Name
                        
                        equals new
                        
                            accountNo = farmerFromList.AccountNo,
                            name = farmerFromList.Name
                        
                        select new
                        
                            farmerProfile.Name,
                            farmerProfile.BankName,
                            farmerProfile.BranchName,
                            farmerProfile.AccountNo
                        ;

如果您只打算通过 duplicateChecklist 一次,那么离开 .ToList() 会更好地提高性能。

【讨论】:

以上是关于我可以使用 linq 将表加入列表吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

linq 连接中是不是存在“不相等”? [复制]

LINQ To Objects - 加入空列表

加入集合的 LINQ 更新

linq 加入 case 条件

将 3 个列表组合成 1 个 LINQ 查询 C#

如何使用 LINQ 从列表中获取重复项? [复制]