【问题标题】:Simplifying nested foreach loop that has if statement with one lambda expression使用一个 lambda 表达式简化具有 if 语句的嵌套 foreach 循环
【发布时间】:2017-03-17 16:34:51
【问题描述】:

正如标题所指定的,我有一个旅行列表,一个旅行有一个票列表,每张票都与一个客户相关联。

我想将每个票务客户 ID 与我的可变客户 ID 进行比较,以仅获取该客户的票,并且我希望获得该客户拥有票的旅行列表。

   Customer customer = db.Customers.FirstOrDefault(u => u.UserId.Equals(user.Id));
   List<Ticket> Tickets = new List<Ticket>();
   List<Trip> Trips = new List<Trip>();

    foreach (Trip trip in db.Trips)
    {
        trip.Tickets.ForEach(ticket =>
            {
                if (ticket.Customer.UserId == customer.UserId)
                {
                    Tickets.Add(ticket); //Add the trip to Trips
                }
            }
        );
    }

我想到但无法运行的代码

    Trips = db.Trips.Select(trip => trip.Tickets.FirstOrDefault(ticket =>
        {
            if (ticket.Customer.UserId == customer.UserId)
            {
                Tickets.Add(ticket);
            }
        })).ToList();

【问题讨论】:

  • 那是什么问题?
  • @M.kazemAkhgary 如何将我现在拥有的代码替换为一个 lambda 表达式,该表达式既可以创建客户有票的旅行列表,也可以将这些票添加到另一个列表。跨度>

标签: c# asp.net-mvc lambda


【解决方案1】:

类似下面的东西应该可以工作 - 虽然未经测试,但应该让你接近。

List<Trip> trips = db.Trips.ToList();
List<Ticket> tickets = new List<Ticket>()
trips.ForEach(p => tickets.AddRange(p.Tickets.Where(q => q.Customer.UserId == customer.UserId)));

编辑 - 如果您想为客户获取旅行列表,然后是门票列表,我会稍有不同:

//get a list of customer trips
List<Trip> trips = db.Tickets.Where(p => p.Customer.UserId == customer.UserId).Select(q => q.Trip).ToList();
List<Ticket> tickets = trips.select(p => p.Tickets.Where(q => q.Customer.UserId == customer.UserId).ToList()).ToList();
//or if you're not bothered about hitting the db again:
//List<Ticket> tickets = db.Tickets.Where(p => p.Customer.UserId == customer.UserId).ToList();

【讨论】:

  • 是的,但是是否有可能只在旅行中保存该客户有票的旅行,而不是使用 db.Trips.ToList(),我正在尝试获取列表客户去过的旅行和客户的票
  • List Trips = db.Trips.Select(trip => Tickets.AddRange(trip.Tickets.Where(q => q.Customer.UserId == customer.UserId)))。列表(); - 这基本上就是我想要得到的,用户有票的旅行列表并将这些票添加到另一个列表
  • @Rick Cheers,我的票仍然有一个小问题,错误是无法将 IEnumerable 转换为通用列表,可以正常使用额外的数据库调用,但当我尝试重用旅行列表时却不行跨度>
  • 您的第一个代码会导致所有不必要的行程。第二个很困惑,你已经只过滤了客户的票,为什么还要在trips对象中再次过滤呢?另外,里面有where 的select 似乎不起作用,那应该怎么做?
  • @Alisson - 问题是关于 lamda,而不是访问数据库的最有效方法。第二个示例获取客户拥有机票的所有旅行 - 但是 - 旅行对象仍将包含所有客户的机票 - 因此再次过滤客户 ID。
【解决方案2】:
var tickets = db.Trips
    .SelectMany(trip => trip.Tickets)
    .Where(ticket => ticket.Customer.UserId == customer.UserId)
    .ToList();

喜欢吗?

【讨论】:

    【解决方案3】:

    要仅获得客户拥有的门票:

    List<Ticket> tickets = db.Tickets
                           .Where(t => t.Customer.UserId == customer.UserId)
                           .ToList();
    

    要获得至少为您的客户提供一张票的所有旅行:

    List<Trip> trips= db.Trips
                      .Where(t => t.Tickets.Any(ti => ti.Customer.UserId == customer.UserId))
                      .ToList();
    

    但是,这不会加载票证。如果您还想加载 trips 和他们的 tickets,只需像这样添加 Include():

    List<Trip> trips= db.Trips.Include("Tickets")
                      .Where(t => t.Tickets.Any(ti => ti.Customer.UserId == customer.UserId))
                      .ToList();
    

    无需查询客户。

    【讨论】:

    • 最后一个包含 Include 的选项是否仅包含该客户对该旅行列表的门票?由于我使用延迟加载,因此默认情况下 db.Trips 已加载所有票证
    • Include 将在一个查询中为每个Trip 急切地加载所有Tickets。在没有Include 的情况下查询时,查询只会得到Trip,然后由于延迟加载,当您尝试为每个Trip 获取Tickets 时,将执行一个新查询来填充票证。如果你有 100 张票并遍历所有票,这意味着将执行 100 次查询来加载每个 Trip 的 Ticker,这非常慢。如果您使用Include,它们将已经被一个查询填充,这样更快。
    • 但是,回答您的问题时,它只会获得 trips,其中您的用户至少有一张 ticket,但 Include 会获取这些旅行的所有门票,包括其他客户的门票。延迟加载也会这样做。很难理解你想要什么.....你需要 Trip 对象吗?还是您只需要Tickets?如果只需要Tickets,直接查询Tickets,而不是获取Trips。
    猜你喜欢
    • 1970-01-01
    • 2017-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多