以下假设为 EF Core 5,which now automatically creates many-to-many relationships,您无需为连接表添加实体类(这在之前的 EF Core 版本中是必需的)。
// Entity classes
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public ICollection<Hobby> Hobbies { get; set; }
public ICollection<Class> Classes { get; set; }
}
public class Class
{
public int ClassId { get; set; }
public string ClassName { get; set; }
public ICollection<Student> Students { get; set; }
}
public class Hobby
{
public int HobbyId { get; set; }
public string HobbyName { get; set; }
public ICollection<Student> Students { get; set; }
}
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Class> Classes { get; set; }
public DbSet<Hobby> Hobbies { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Student>().HasKey(c => new { c.StudentId });
modelBuilder.Entity<Class>().HasKey(c => new { c.ClassId });
modelBuilder.Entity<Hobby>().HasKey(h => new { h.HobbyId });
}
}
这是一个简单的控制器操作,它在 get 操作中使用单个 EF Core 5 查询语句来查询学生及其爱好和课程:
private readonly AppDbContext _dbContext;
public HomeController(AppDbContext dbContext, ILogger<HomeController> logger)
{
_dbContext = dbContext;
_logger = logger;
}
[HttpGet]
public IActionResult Index()
{
var students = _dbContext.Students
.Include(s => s.Hobbies)
.Include(s => s.Classes)
.ToList();
var filterableStudentListing = new FilterableStudentsListing
{
Students = students,
StudentClasses = students.SelectMany(s => s.Classes).Select(c => new SelectListItem { Text = c.ClassName, Value = c.ClassId.ToString() }).Distinct().ToList(),
StudentHobbies = students.SelectMany(s => s.Hobbies).Select(c => new SelectListItem { Text = c.HobbyName, Value = c.HobbyId.ToString() }).Distinct().ToList()
};
return View(filterableStudentListing);
}
[HttpPost]
public IActionResult Index(FilterableStudentsListing model)
{
// Demonstrates the new EF Core 5 filtered include, but you actually would not want to do this in a real app.
var students = _dbContext.Students
.Include(s => s.Hobbies.Where(h => h.HobbyId == model.SelectedHobbyId))
.Include(s => s.Classes.Where(c => c.ClassId == model.SelectedClassId))
.ToList();
var filterableStudentListing = new FilterableStudentsListing
{
Students = students,
StudentClasses = students.SelectMany(s => s.Classes).Select(c => new SelectListItem { Text = c.ClassName, Value = c.ClassId.ToString() }).Distinct().ToList(),
StudentHobbies = students.SelectMany(s => s.Hobbies).Select(c => new SelectListItem { Text = c.HobbyName, Value = c.HobbyId.ToString() }).Distinct().ToList()
};
return View(filterableStudentListing);
}
澄清我在发布操作中的代码注释,在任何实际应用程序中使用 EF Core 过滤包含不是一个好主意的原因是,您会为用户剥离可能的选择选项以每次选择过滤器选项以过滤数据时选择。在真正的应用程序中,您只需在使用与 get 操作中完全相同的查询后过滤视图模型中的学生。我只是想演示过滤包含,因为它是 EF Core 中的新热点。
这是一个简单的剃须刀视图,显示学生的课程和爱好:
@model FilterableStudentsListing
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Example</h1>
</div>
<div>
<form id="form1" method="post">
<select asp-for="SelectedClassId" asp-items="@Model.StudentClasses"> </select>
<select asp-for="SelectedHobbyId" asp-items="@Model.StudentHobbies"></select>
<button type="submit">Filter</button>
</form>
</div>
<div>
@foreach (var student in Model.Students)
{
<h4>@student.StudentName</h4>
<h5>Classes</h5>
<ul>
@foreach (var c in student.Classes)
{
<li>@c.ClassName</li>
}
</ul>
<h5>Hobbies</h5>
<ul>
@foreach (var h in student.Hobbies)
{
<li>@h.HobbyName</li>
}
</ul>
}
这是剃刀视图的简单模型类:
public class FilterableStudentsListing
{
public List<Student> Students { get; set; }
public List<SelectListItem> StudentHobbies { get; set; }
public List<SelectListItem> StudentClasses { get; set; }
public int SelectedClassId { get; set; }
public int SelectedHobbyId { get; set; }
}