【问题标题】:LINQ to entities Child queries where Parent has certain propertiesLINQ to entity Child 查询其中 Parent 具有某些属性
【发布时间】:2012-04-27 10:49:35
【问题描述】:

使用 C# 和 LINQ 到实体我遇到了子实体和父实体搜索的问题。从概念上讲,我试图获得一个 IEnumerable 孩子的集合,其中这些孩子具有某些属性,并且这些孩子的父母也具有某些属性。

具体来说,我有具有多对多关系的 Routes 和 Streets。我正在尝试在特定路线上查找街道,其中街道具有 LeftNote 或 RightNote 的正属性(LeftNote 和 RightNote 是字符串,我正在搜索非空格的字符串)。

我有以下实体(为了清楚起见,删减)

public class Route
{
    public int RouteID { get; set; }

    public virtual ICollection<Street> Streets { get; set; }
}

public class Street
{
    public string LeftNote { get; set; }

    public string RightNote { get; set; }

    public virtual ICollection<Route> Routes { get; set; }
}

我有以下 LINQ 表达式:

var streets = this.repository.Routes
                        .Where(r => r.RouteID == routeId).FirstOrDefault()
                        .Streets
                        .Where(s => s.LeftNote.Length > 0 || s.RightNote.Length > 0);

在我对存在 Route 但没有包含 LeftNotes 或 RightNotes 的街道的实体数据运行此操作之前,这非常有效。在这些情况下,我得到一个 NullReference 异常。我正在尝试找到一种方法来正确表达此查询,该查询使用 LeftNotes 处理 Streets 的缺失(应该始终有一个与 routeId 匹配的 Route。如果不是,这是一个有效的异常情况,应该抛出错误)。

编辑:问题似乎与空字符串有关,而不是与 LINQ 构造相关的任何内容。

【问题讨论】:

    标签: c# linq linq-to-entities


    【解决方案1】:

    你说的是真的

    var streets = repository.Streets.Where
           (s => s.Routes.Any(r => r.RouteID == routeId )
                 && (s.LeftNote.Length > 0 || s.RightNote.Length > 0));
    

    【讨论】:

    • Routes 没有 LeftNote 和 RightNote,而 Streets 有它们。
    • 我会按照你的描述测试一下
    【解决方案2】:
    var streets = this.repository
                      .Routes
                      .Where(r => r.RouteID == routeId).FirstOrDefault()
                      .Streets
                      .Where(s => s.LeftNote !=null ? s.LeftNote.Length > 0 : false
                              || s.RightNote !=null ? s.RightNote.Length > 0 : false);
    

    尚未对其进行测试,但认为它应该可以工作。

    this.repository.Streets(s=>(s.LeftNote.Length >0 || s.RightNote.Length > 0 ) 
                                 && s.Routes.routeId==routeId));
    

    【讨论】:

    • 第一个选项编译并执行,但与我想要的相反(无论关系如何,它都会返回路线上的所有街道)。第二个选项需要找到某种方式来遍历路由集合。 Routes.routeId 不合法。
    • 将两个返回值都设为false,它现在应该可以工作了。 (见编辑)
    【解决方案3】:

    只需使用 String.IsNullOrEmpty()。

    var streets = this.repository
                    .Routes
                    .Where(r => r.RouteID == routeId).FirstOrDefault()
                    .Streets
                    .Where(s => !String.IsNullOrEmpty(s.LeftNote) ||
                                !String.IsNullOrEmpty(s.RightNote));
    

    【讨论】:

    • @AlexC FirstOrDefault 实现查询,因此之前的部分在服务器上运行(在 SQL 中),之后的部分在本地运行。您可以通过在服务器上运行整个查询来提高效率(如有必要)。
    • @Phil,你建议怎么做?
    • 好吧,我的答案是尝试一下。不确定它是否完全按照您的要求工作。如果您使用 LINQPad,您可以在测试 LINQ 时看到生成的 SQL。
    • @AlexC,根据定义,FirstOrDefault() 也可以返回 NULL,因此如果 routeId 不存在,您现在将获得一个 null-ref。
    【解决方案4】:

    必须在一个查询中执行吗

    IEnumerable<Street> streets = Enumerable.Empty<Street>();
    var route = this.repository
                    .Routes
                    .Where(r => r.RouteID == routeId).FirstOrDefault()
    
    if(route != null && route.Streets.Any())
    {
        streets = route.Streets
                       .Where(s => s.LeftNote.Length > 0 
                                || s.RightNote.Length > 0);
    }
    

    【讨论】:

      【解决方案5】:

      请尝试以下方法:

      var streets = this.repository.Routes
                                   .Where(r => r.RouteID == routeId).FirstOrDefault()
                                   .Streets
                                   .Where(s => s.LeftNote ? s.LeftNote.Length > 0 : false || s.RightNote ? s.RightNote.Length > 0 : true);
      

      更新

      var streets = this.repository.Streets
                                   .Where(s => s.Routes.RouteID == routeId && s.LeftNote.Length > 0 || s.RightNote.Length > 0);
      

      在插入新代码之后更新代码。

      使用 false first 的原因是强制验证 second or 子句。不确定以下是否有效。

      【讨论】:

      • @Flowerking:抱歉,我想输入? 而不是??。感谢您指出这一点。我已经更新了我的代码。
      • 这不会编译,因为您试图将字符串分配给 s.LeftNote 中的 false 布尔值? s.LeftNote.Length > 0 : false 和 s.RightNote 中布尔值 true 的字符串? s.RightNote.Length > 0:真。我对您可能暗示的解决方案感兴趣,但就目前而言,这对我来说没有多大意义。
      • assign a string to the boolean value 怎么样? s.LeftNote.Length&gt;0 是布尔值,所以 false 是。没看懂,请解释一下
      【解决方案6】:

      尝试将 LINQ 表达式更改为此

      var streets = this.repository.Routes
                        .Where(r => r.RouteID == routeId).FirstOrDefault()
                        .Where(r => r.Streets.Any(s => s.LeftNote.Length > 0 || s.RightNote.Length > 0));
      

      【讨论】:

        猜你喜欢
        • 2012-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多