根据另一个列表的条件筛选列表

3
我有两个列表,一个包含客户端传来的数据,另一个则来自我的数据库,这意味着这些数据已经存在于我的数据库中。
我尝试的目标是,根据客户端的列表,筛选出不包含在我的数据库列表中的数据,以便在插入之前处理非重复项。
为了过滤这些数据,我尝试使用带有多个条件的LINQ(银行数据)。
  List<BalanceQuery> result = new List<BalanceQuery>();

  clientList.ForEach(y =>
  {
    result = dbList.Where(x =>
      (y.BankCode != x.BankCode) ||
      (y.Agency != x.Agency) ||
      (y.AccountNumber != x.AccountNumber)).ToList();
  });

但由于某些原因,它没有正常工作。有什么想法吗?

谢谢

3个回答

1

假设你有一个如下所示的类:

class CustomerInformation
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

正如你所说,你有两个列表,假设你的两个列表如下:

List<CustomerInformation> dbList = new List<CustomerInformation>
        {
            new CustomerInformation{Id=1, FirstName="Raju",   LastName="Ahmed"},
            new CustomerInformation{Id=2, FirstName="Tahira", LastName="Biswas"},
            new CustomerInformation{Id=3, FirstName="Shohag", LastName="Mia"},
            new CustomerInformation{Id=4, FirstName="Saiful", LastName="Islam"}
        };

        List<CustomerInformation> csutomerList = new List<CustomerInformation>
        {
            new CustomerInformation{Id=1, FirstName="Raju",   LastName="Ahmed"},
            new CustomerInformation{Id=2, FirstName="Tahira", LastName="Biswas"},
            new CustomerInformation{Id=3, FirstName="Shohag", LastName="Mia"},
            new CustomerInformation{Id=4, FirstName="Saiful", LastName="Islam"},
            new CustomerInformation{Id=5, FirstName="Anny", LastName="Bishwas"},
            new CustomerInformation{Id=6, FirstName="Kabita", LastName="Roy"},
            new CustomerInformation{Id=7, FirstName="Zahidul", LastName="Emon"}
        };

现在您想获取那些在客户列表中不存在,但具有某些特定条件的数据库列表,请尝试以下操作:

 var newList = csutomerList.Where(cusItem => !dbList.Any(dbItem => cusItem.Id == dbItem.Id && cusItem.FirstName == dbItem.FirstName && cusItem.LastName == dbItem.LastName));

它将首先找出两个列表中都存在的所有数据,然后简单地将它们减去。

enter image description here

完整代码如下:

    static void Main(string[] args)
    {
        AvailableData();
        Console.ReadKey();
    }

    public static void AvailableData()
    {
        // Create two lists.
        List<CustomerInformation> dbList = new List<CustomerInformation>
        {
            new CustomerInformation{Id=1, FirstName="Raju",   LastName="Ahmed"},
            new CustomerInformation{Id=2, FirstName="Tahira", LastName="Biswas"},
            new CustomerInformation{Id=3, FirstName="Shohag", LastName="Mia"},
            new CustomerInformation{Id=4, FirstName="Saiful", LastName="Islam"}
        };

        List<CustomerInformation> csutomerList = new List<CustomerInformation>
        {
            new CustomerInformation{Id=1, FirstName="Raju",   LastName="Ahmed"},
            new CustomerInformation{Id=2, FirstName="Tahira", LastName="Biswas"},
            new CustomerInformation{Id=3, FirstName="Shohag", LastName="Mia"},
            new CustomerInformation{Id=4, FirstName="Saiful", LastName="Islam"},
            new CustomerInformation{Id=5, FirstName="Anny", LastName="Bishwas"},
            new CustomerInformation{Id=6, FirstName="Kabita", LastName="Roy"},
            new CustomerInformation{Id=7, FirstName="Zahidul", LastName="Emon"}
        };


        var newList = csutomerList.Where(cusItem => !dbList.Any(dbItem => cusItem.Id == dbItem.Id && cusItem.FirstName == dbItem.FirstName && cusItem.LastName == dbItem.LastName)); 

       foreach (var cust in newList)
        {
            Console.WriteLine("Customer Id :{0} | Customer Name: {1} | Last Name: {2} ",cust.Id,cust.FirstName,cust.LastName);
        }
        Console.ReadKey();

    }
}

class CustomerInformation
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

0
一个更加LINQ的方法是这样的。我已经测试过了。
 result =
        (from cl in clientList 
         where !dbList.Any(x => x.AccountNumber == cl.AccountNumber && x.BankCode == cl.BankCode && x.Agency == cl.Agency)
         select cl).ToList();

0

初步

本答案假定您正在使用ORM,例如EF或EF Core。代码未经过测试,仅在此处为您提供正确的解决方向。一些开放性问题需要回答才能达到最终解决方案。

此外,您的问题有时似乎是矛盾的:您提到客户端列表,而您展示的函数返回一个List<PrePaymentBalanceQuery>。我在这里假设我们正在谈论客户端列表,并且我可以忽略一些不清楚的点。无论如何,如果我错了,请告诉我,我要么编辑这个答案,要么删除它。

分析现有代码和问题

由于代码没有实现您想要的功能,让我们先了解它的作用。

您想要根据存储在数据库中的某些数据来过滤内存中的Client列表。

clientList.ForEach(y =>
{
    result = dbList.Where(x =>
      (y.BankCode != x.BankCode) ||
      (y.Agency != x.Agency) ||
      (y.AccountNumber != x.AccountNumber)).ToList();
});

return result;

这段代码没有过滤Client列表。

它所做的是,对于每个Client

  • 计算某些内容并将其存储到名为result的变量中。

因此,在每次迭代中,变量result中的内容都会被新内容替换。

最终,变量result仅包含为最后一个客户端进行的计算,这不是您想要实现的目标。

结论:在此处不应使用ForEachForEach不是过滤运算符。 Linq具有过滤运算符:Where,应在此处使用。

附注:ForEach不是Linq方法扩展。它是List类的方法。 起初可能会感到惊讶,但这是有充分理由的。 ForEach不是纯函数(在函数式编程意义上),它会引入副作用,因此违反了Linq的一般原则。 Linq不强制执行纯度,但通常是可取的。

如何尝试解决这个问题

这是一个过滤clientList的第一个版本:

var FilteredClientList = clientList.Where(c => !dbList
      .Any(dbc =>
          (c.BankCode == dbc.BankCode)
          && (c.Agency == dbc.Agency)
          && (c.AccountNumber == dbc.AccountNumber))
  );

return FilteredClientList;

它通过仅在数据库中不存在此类客户的情况下,从clientList保留客户来构建新的客户端列表。

如果存在具有相同Bankcode,相同Agency和相同AccountNumber的数据库客户端,则认为内存中的客户端已存在于数据库中。

但是,存在一个问题。虽然这在功能上可以工作,但它可能会对您的数据库进行大量调用:每个客户一个调用。

要理解这一点,您必须了解Linq to Objects和Linq to Entities之间的区别。

请参见linq to entities vs linq to objects - are they the same?

如何解决这个问题?这取决于您的具体情况。 如果您的客户列表很小,您可以保持不变,并愿意为每个客户支付一个SQL查询。

如果您的数据库列表很小,您可以首先将其保存在内存中,并在内存中执行所有工作。

var ClientsFromDb = dbList.
    .Select(c => new 
    {
        c.BankCode,
        c.Agency,
        c.AccountNumber
    })
    .ToList()
    
var FilteredClientList = clientList.Where(c => !ClientsFromDb
      .Any(cc =>
          (c.BankCode == cc.BankCode)
          && (c.Agency == cc.Agency)
          && (c.AccountNumber == cc.AccountNumber))
  );

通过使用Join运算符,这也可以得到改进。

但是如果您的数据库客户端列表太大怎么办?

您可以首先在一个数据库查询中检索所有匹配的客户端,然后使用该内存列表来过滤实际列表。

有关指针,请参见Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接