joa*_*car 4 entity-framework-core asp.net-core-mvc
我有以下多对多关系建模
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;}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用 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);
}
Run Code Online (Sandbox Code Playgroud)
从这一点来看, Profile 对象是不同的,其他导航属性(例如 Platforms)为空,因此破坏了其他部分。
如何在保留 Profile 对象的原始实例的同时执行连接。我一开始以为它们是一样的,但我错了。
目前,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();
Run Code Online (Sandbox Code Playgroud)
2) 根据已知 ID 选择所需数据:
var result = await _context.Profiles
.Include(p => p.Categories).Include(p => p.Platforms)
.Where(x => profileIds.Contains(x.ProfileId))
.ToListAsync();
Run Code Online (Sandbox Code Playgroud)
是的,这是两个查询而不是一个,但是两个简单的查询,使用索引很容易优化。
归档时间: |
|
查看次数: |
3315 次 |
最近记录: |