【问题标题】:ArgumentException on navigation property query in LINQLINQ 中导航属性查询的 ArgumentException
【发布时间】:2016-03-24 23:30:30
【问题描述】:

我在使用 Entity Framework 6 的 Visual Studio 2015 WPF 应用程序中有以下 LINQ 查询:

var query = Context.Services.AsQueryable();

Services 实体具有以下导航属性:

public virtual ICollection<ServiceStatu> ServiceStatus { get; set; }

一个服务可以有 0 个或多个 ServiceStatus。我正在尝试使用Include 获取状态等于 7 的服务:

query = query.Include(x => x.ServiceStatus.Where(p => p.serviceStatusID == 7));

但它抛出了这个异常:

EntityFramework.dll 中出现“System.ArgumentException”类型的异常,但未在用户代码中处理

附加信息:包含路径表达式必须引用在类型上定义的导航属性。对引用导航属性使用虚线路径,对集合导航属性使用 Select 运算符。

请注意,我曾尝试使用 JOINs 执行此操作,但这很丑,所以我决定使用内置的导航属性。

我做错了什么?谢谢。

【问题讨论】:

  • Include 用于急切地加载所有内容。它不能包含过滤器 (Where)。
  • 谢谢,@IvanStoev。那么我该如何解决这个问题以引用 nav 属性并对其进行过滤?
  • where 放在include 方法调用之后,而不是放在里面。
  • 如果你只是想获得状态为7的服务,那么你可以使用var query = Context.Services.Where(x =&gt; x.ServiceStatus.Any(s =&gt; s.serviceStatusID == 7))
  • 我正在处理 Services 实体(不在我上面的代码中),然后将其添加到该查询中

标签: c# entity-framework linq


【解决方案1】:

很遗憾,您无法在 Include 调用中过滤导航属性。正如异常所说,您需要引用导航属性。要过滤您的导航属性,您需要将查询投射到匿名类型或 DTO,例如:

query = query.Include(x => x.ServiceStatus)
             .Select(s=>new {
                              //other properties that you need to project
                              Status=s.ServicesStatus.Where(p => p.serviceStatusID == 7)
                            });

在加载时过滤相关实体的一种方法是使用Explicit Loading

 var service= query.FistOrDefault();// this is an example to use a service instance
 context.Entry(service) 
        .Collection(b => b.ServiceStatus) 
        .Query() 
        .Where(ss => ss.Where(p => p.serviceStatusID == 7) 
        .Load(); 

【讨论】:

  • 谢谢,@octavioccl。第一个示例给出了错误,说它不能将 ServiceStatus 隐式转换为 Services;我的查询是在服务上创建的,我在此之前运行了其他 Where 子句。
  • 您能否发布整个查询以查看更多详细信息您在做什么?
【解决方案2】:

您不能在Include 语句上使用Where,请在Include 之后应用任何过滤器。

您可以在 Context 构造函数中禁用 延迟加载

class EfContext : DbContext
{
    public EfContext()
    {
        Configuration.LazyLoadingEnabled = false;
    }

    ...

那么,如果您在ServiceStatu 模型中定义了ServiceId 属性:

Service service = ...;
context.ServiceStatus.Where(s => ServiceId == service.Id).Load()

context.Entry(service).Collection(s => s.ServiceStatu).Load()

但是,一旦您加载属于该service 的另一个ServiceStatuEF 会将其添加到service 的集合中。

在您的情况下,您可以使用 延迟加载 并投影结果或过滤状态并将其存储在另一个变量中:

var newQuery = query.Select(s => new { Service = s, FilteredStatus = s.ServiceStatu.Where(ss => ss.ServiceStatusID == 7) });

//or

var status = service.ServiceStatu.Where(s => s.ServiceStatusID == 7);

【讨论】:

  • 使用你的第一个代码示例,它告诉我'Services' does not contain a definition for 'serviceStatusID',所以它不会编译
  • @Alex:对不起,我忘了ServiceStatus属性
  • 现在是'ServiceStatu' does not contain a definition for 'serviceStatusID'。注意ServiceStatu的拼写
  • @Alex:哦,我明白了,我要更新我的答案,但你不能只加载某些状态,至少在延迟加载中是这样
  • 谢谢,@ArturoMenchaca。那我怎样才能让它急于加载呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多