在导航属性中搜索

时间:2012-09-16 01:31:10

标签: asp.net-mvc linq ef-code-first

我已经在ASP.NET MVC 4中使用代码优先方法创建了我的应用程序。

我有三个实体。即,“公司”,“服务”和“服务特征”:

public class Company
{
    public int CompanyID { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public string Description { get; set; }

    public virtual Service SuppliedService { get; set; }

}

public class Service
{
    public int ServiceID { get; set; }

    [Required]
    public string Name { get; set; }

    public virtual ICollection<ServiceFeature> ServiceFeatures { get; set; }

}    

public class ServiceFeature
{
    public int ServiceFeatureID { get; set; }

    [Required]
    public string Name { get; set; }


}

我有一个搜索表单,它包含所有ServiceFeatures的复选框。用户将选中复选框,并获取为所选服务提供服务的公司的结果。

我使用我的服务获取公司列表,如下所示,但我仍然坚持如何将选定的ServiceFeatures包含在where子句中(带有for循环的动态LINQ?)

var searchResults = _companyService.GetCompanies();

2 个答案:

答案 0 :(得分:0)

假设您有一个包含所选功能的ID的集合,名为requested,并假设您希望公司提供包含所有选定功能的服务,您可以这样做:

var q = from c in searchResults
        let sf = c.SuppliedService.ServiceFeatures
                                  .Select(f => f.ServiceFeatureID)
                                  .Intersect(requested)
        where sf.Count() == requested.Count()
        select c;

答案 1 :(得分:0)

在类似的情况下,我更喜欢一种比使用Intersect的linq查询更精细的方法。 Intersect可以使用深度嵌套生成可怕的查询,因为ID值要相交的列表是由列表中每个Id的SELECTUNION命令构建的。当Id的数量很少时,这不是问题(在我的情况下,我认为是真的),但是如果数字较大,则可能引发SQL异常。

所以这是我更喜欢的:

var q = context.Companies.AsQueryable();

foreach(int i in featureIds)
{
    int j = i; // prevent modified closure.
    q = q.Where(c => c.SuppliedService.ServiceFeatures.Any(f => f.Id == j));
}

var result = q.ToList();

它使用多个WHERE EXISTS子句构建查询。这可能非常有效,因为每个EXISTS将寻找(不扫描)ServiceFeature的主索引。除此之外,INTERSECT是隐式DISTINCT

嗯,只是想指出这一点。如上所述,由于记录数量较少,您不会发现任何差异。所以,不管你最适合什么。