我怎样才能使一个更有效的实体框架LINQ调用比嵌套循环

本文关键字:实体 有效 框架 LINQ 嵌套循环 调用 一个 | 更新日期: 2023-09-27 18:03:51

是否有更有效的方法来编写这个LINQ语句?

Feature使用与Product相同的模型(因为它们几乎相同)。

var products = db.Products.Where(q => q.IsFeature == false).ToList();
        foreach (Product pr in products)
        {
            var features = db.Products.Where(q => q.ParentID == pr.ID).ToList();
            foreach(Product feature in features)
            {
                pr.Features.Add(feature);
            }
        }

和模型:

    public class Product
{
    //START
    public Product()
    {
        Features = new HashSet<Product>();
    }
    public int ID { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public bool IsFeature { get; set; }
    public int ParentID { get; set; }// If IsFeature is true we need to know its parent
    //Nav Props
    public ICollection<Product> Features { get; set; }// Features can be represented with the same model as product as they are almost identical
}

这就是我需要的产品列表(Products),每个产品都有自己的功能列表(Features),但是否有更优雅/有效的替代方案?

我怎样才能使一个更有效的实体框架LINQ调用比嵌套循环

你需要的是一个join:

var productFeatures = 
    db.Products.Where(q => !q.IsFeature)
    .Join(db.Products, p => p.ID, f => f.ParentId, (p, f) => new { product: p, features: f.ToList() })
    .ToList();

对于db.Products.Where(q => !q.IsFeature)中的每个对象,这将找到ParentId等于其ID字段的每个db.Products

结果将被投影到具有字段product (Product)features (List<Product>)的匿名类型的List()

如果该操作的复杂性上升到生成Linq的SQL成为障碍的程度,或者该业务逻辑在多个地方完成;考虑将逻辑放在存储过程中。

一旦进入数据库,只需将结果映射到EF中,稍后可以很容易地被代码使用。因此,复杂性从客户端转移到数据库。

Steps (Database First)

  1. 创建存储过程。
  2. 从数据库中更新模型并选择存储过程。
  3. 验证EF的Model Browser中的结果映射。
  4. 从数据上下文中使用命名的存储过程。

我在我的博客文章实体框架存储过程说明中讨论了映射存储过程的细节。

你可以使用Addrange方法的列表集合:

var products = db.Products.Where(q => !q.IsFeature).ToList();
foreach(Product pr in db.Products)
  if(!pr.IsFeature) pr.Features.AddRange(db.Products.Where(q => q.ParentID == pr.ID));

注:另一个想法是提取特征,对它们进行排序,转换为数组并使用for循环:

var features = db.Products.Where(q => q.IsFeature).OrderBy(f => f.ParentID).ToArray();    
p = db.Products.First(p => p.ID == features[0].ParentID);
for(int i = 0; i < features.Length; i++ ) 
{
   if(i > 0 && features[i - 1].ParentID != features[i].ParentID)
     p = db.Products.First(p => p.ID == features[i].ParentID);
   p.Features.Add(features[i]);
}

您需要使用GroupJoin。这正是它的设计目的。

var products = db.Products.Where(p => !p.IsFeature)
    .GroupJoin(db.Products, p => p.ID, q => q.ParentID, (p, eq) => {
        p.Features = eq.ToList();
        return p;
    })
    .ToList();

此代码未经测试,但应该可以工作。