EF Core多对多提取查询

时间:2016-12-02 13:38:51

标签: asp.net-core-mvc entity-framework-core

我有以下多对多关系建模

public class Profile
{
ICollection<Category> Categories { get; set;}
// One-To-Many
ICollection<Platform> Platforms { get; set; }
}

public class Category
{
ICollection<Profile> Profiles { get; set; }
}

public class ProfileCategory
{
public int ProfileId { get; set; }
public Profile Profile { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set;}
}

我正在使用ASP.NET Core MVC并且有一个过滤器视图模型,其中对配置文件名称上的某些属性进行过滤并且它可以正常工作。

尝试基于类别进行过滤被证明更难实现(至少解决方案对我来说并不明显:)

在网络上,用户可以选择零,一个或多个类别进行过滤,因此基本上发送给我的控制器的是类别ID列表。

IQueryable<Profile> query = _context.Profiles.Include(p => p.Categories).Include(p => p.Platforms);
if(string.IsNullOrEmpty(search.Name))
{
query = query.Where(p => p.Name.IndexOf(search.Name StringComparison.OrdinalIgnoreCase) > 0);
}
if(search.Categories?.Any() != null)
{
    query = query.SelectMany(p => p.ProfileCategories)
            .Join(search.Categories, pc => pc.CategoryId, cId => cId, (pc,_) => pc.Profile);
}

从这一点来看,Profile对象是不同的,其他导航属性(如Platforms)为null,因此会破坏其他部分。

如何在保留Profile对象的原始实例的同时执行连接。我首先想到他们会是一样的,但我错了。

1 个答案:

答案 0 :(得分:3)

目前,EF Core JOIN并不完美,我建议进行两次查询:

1)选择ProfileId列表(基于类别列表):

var profileIds = await _context.ProfileCategory
    .Where(x => categoryIds.Contains(x.CategoryId)) // filtering goes here
    .Select(x => x.ProfileId)
    .Distinct()
    .ToListAsync();

2)根据已知ID选择所需数据:

var result = await _context.Profiles
    .Include(p => p.Categories).Include(p => p.Platforms)
    .Where(x => profileIds.Contains(x.ProfileId))
    .ToListAsync();

是的,这是两个查询而不是一个,但是两个简单的查询,可以使用索引轻松优化。