LINQ中导航属性查询的ArgumentException

时间:2016-03-24 14:39:24

标签: c# entity-framework linq

我在使用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'类型的异常,但未在用户代码中处理

     

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

请注意,我曾尝试使用JOIN执行此操作,但这很难看,所以我决定使用内置的nav属性。

我做错了什么?感谢。

2 个答案:

答案 0 :(得分:2)

很遗憾,您无法在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(); 

答案 1 :(得分:1)

您无法在Where语句中使用Include,请在Include之后应用任何过滤器。

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

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

    ...

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

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

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

但是,只要您加载属于该ServiceStatu的其他service EF 就会将其添加到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);