【问题标题】:Filter list of entity objects by string child object property using Linq Lambda使用 Linq Lambda 按字符串子对象属性过滤实体对象列表
【发布时间】:2019-05-15 11:51:02
【问题描述】:

我正在尝试返回由子对象属性 Owner.Name 过滤的 IQueryable 土地。与查询样式解决方案配合良好,但我想使用 lambda 解决方案。

简而言之,这些是我由 EntityFramework 映射的类:

public class Land
{
     public int Id { get; set; }

     public virtual ICollection<Owner> Owners { get; set; }
}

public class Owner
{
        public int Id { get; set; }
        public string Name { get; set; }
        public int LandId { get; set; }

        public virtual Land Lands { get; set; }
}

运行良好的查询:

 var list = from land in db.Lands
                   join owner in db.Owners on land.Id equals Owner.LandId
                   where owner.Name.Contains("Smit")
                   select land;

我正在尝试使用这个:

var list = db.Lands.Where(lnd => lnd.Owners.Count() > 0 &&
             lnd.Owners.Where(own => own.Name.Contains("Smit")).Count() > 0);

它只适用于小列表,但对于一些有数千条记录的列表,它会超时。

【问题讨论】:

  • owner.Name 的属性是从哪里来的?
  • 最好将数据重新排列到像 Lookup 这样的数据结构中,这会使您的查询速度更快,您当前的查询的时间复杂度为 O(N^2),这简直是致命的大量数据的性能,1000 条记录的复杂性变为 100 万次迭代
  • 在实际的Query版本中,你使用的是Join,那为什么不加入Lambda查询,势必会产生影响

标签: c# entity-framework linq lambda


【解决方案1】:

嗯,可能导致速度问题的一个问题是您的 lambda 版本和非 lambda 版本做的事情非常不同。您不是 lambda,正在使用连接一侧的 where 进行连接。

为什么不直接写它的 lambda 表达式呢?

var list = db.Lands.Join(db.Owners.Where(x=> x.Name.Contains("Smit")), a=> a.Id, b => b.LandId, (a,b) => a).toList();

我的意思是,这是你的非 lambda 更直接的等价物

【讨论】:

  • 这是 OP 查询版本的正确替换
【解决方案2】:

我觉得你可以用这个:

var list = db.Lands.Where(lnd => lnd.Owners.Any(x => x.Name.Contains("Smit")));

【讨论】:

    【解决方案3】:

    尝试更直接的方法:

    var lands = db.Owners.Where(o => o.Name.Contains("Smit")).Select(o => o.Lands);
    

    您只需确保 Owner.Name 不为空,其余的由 LINQ 完成。

    【讨论】:

    • 你忘记按 LandId 加入
    • 这种关系应该由实体框架本身来处理。可以使用约定来定义关系,就像上面的例子一样,或者使用 Fluent API 显式定义。
    猜你喜欢
    • 1970-01-01
    • 2020-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多