代码之家  ›  专栏  ›  技术社区  ›  DiPix

如何根据C#中的ID在嵌套列表中填充数据?

  •  4
  • DiPix  · 技术社区  · 7 年前
    public class CarDTO
    {
        public int CarId { get; set; }
        public string CarName { get; set; }
        public List<PolicySummaryDTO> PolicySummaries { get; set; } 
    }
    
    public class PolicySummaryDTO
    {
        public long PolicyId { get; set; }
        public string PolicyName { get; set; }
        public decimal Amount { get; set; }
    }
    

    我有 List<CarDTO> Cars 每辆车都有保险单 List<PolicySummaryDTO> PolicySummaries . PolicyId PolicyName , Amount 我需要做的是从数据库获取数据 _contex.PolicySummary

    1. var policyIds = cars.SelectMany(t => t.PolicySummaries).Select(r => r.PolicyId);

    2. 基于Ids获取策略数据 var policyData = _context.PolicySummary.Where(t => policyIds.Contains(t.PolicyId));

    3. 然后使用 我可以填充数据。

      foreach (var car in cars)
      {
          foreach (var policy in car.PolicySummaries)
          {
              var policyDataToUse = policyData.Single(t => t.PolicyId == policy.PolicyId);
              policy.Amount = policyDataToUse.Amount;
              policy.PolicyName = policyDataToUse.PolicyName;
          }
      }
      

    LINQ JOIN 或者我的解决方案完全正确?


    var policyIds = cars.SelectMany(t => t.PolicySummaries).Select(r => r.PolicyId);
    var policyDict = _context.PolicySummary.Where(t => policyIds.Contains(t.PolicyId)).ToDictionary(t => t.PolicyId);
    
    foreach (var car in cars)
    {
        foreach (var policy in car.PolicySummaries)
        {
            var policyDataToUse = policyDict[policy.PolicyId];
            policy.Amount = policyDataToUse.Amount;
            policy.PolicyName = policyDataToUse.PolicyName;
        }
    }
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   V0ldek    7 年前

    那么首先,为什么数据没有填写?您应该能够在实际操作过程中填写任何相关实体中的数据 Car 使用从数据库获取 .Include .

    var carEntity = _context.Cars.Where(predicate).Include(c => c.PolicySummaries).Single();
    

    其次,代码存在严重的性能问题: policyData 是一个 IQueryable . 每次你这么做 policyData.Single id policyIds 选择合适的。如果有很多政策,这将是非常低效的-每一个 foreach 迭代是一个新的查询!你应该做的可能是:

    var policyData = _context.PolicySummary.Where(t => policyIds.Contains(t.PolicyId)).ToList();
    

    获取所有相关策略。如果有很多共享策略,并且最终在某个时候加载了大部分策略,那么这也可能是低效的,因此如果数据库中没有10亿个这样的策略:

    var policies = _context.PolicySummary.ToList();
    

    foreach公司

        2
  •  0
  •   Fabio    7 年前

    因为已经存在DTO对象(而不是实体),所以无法有效地使用 Join
    您需要加载丢失的数据,然后用它更新现有的汽车对象。

    var allPolicies = _context.PolicySummary
                              .Where(policy => policyIds.Contains(policy.PolicyId))
                              .Select(group => new PolicySummaryDTO
                              {
                                  PolicyId = group.Key,
                                  PolicyName = group.First().PolicyName,
                                  Amount = group.First().Amount                  
                              })
                              .ToDictionary(policy => policy.PolicyId);
    
    foreach (var car in cars)
    {
        car.Policies = car.Policies.Select(p => p.PolicyId)
                                   .Where(allPolicies.ContainsKey)
                                   .Select(policyId => allPolicies[policyId])
                                   .ToList();
    }
    

    使用 Dictionary 将使代码更新更简单,并减少要执行的操作量,减少循环。

    car.Policies Where(allPolicies.ContainsKey) 如果缺少某些策略,将抛出一个异常。