【问题标题】:2x many-to-many queue from database using Entity Framework Core使用 Entity Framework Core 来自数据库的 2x 多对多队列
【发布时间】:2021-01-27 22:29:20
【问题描述】:

这是我苦苦挣扎的地方,例如,您与中心的 Student 建立了 2 x 多对多关系。

你有ClassIDHobbyID,你如何列出所有使用Entity Framework Core的学生(+学生对象内集合中的所有爱好和课程),而不必多次访问数据库或者必须将所有内容都排队。

谢谢:)


编辑:

这是我希望以最少的时间访问数据库来实现的示例。

在您选择下拉选项(可用信息是 ClassID 和 HobbyID)并点击 Filter 按钮后,您应该会得到拥有这些选项的学生。应向学生展示他们所拥有的其他课程和爱好。

不可能从单一访问数据库中将所有内容都排队,否则您将如何做到这一点才能尽可能有效。

对不起,如果我不清楚。我正在尽我所能来解释这一点。谢谢你的耐心! :)

示例设计 =>

<span>Pick a Hoby</span>
<select>
<option value="1">Climbing</option>
<option value="2">Running</option>
<option value="3">Painting</option>
</select>

<span style="margin-left:20px">Pick a Class</span>
<select >
<option value="1">Art</option>
<option value="2">Mathematics</option>
<option value="3">Geography</option>
</select>

<button>Filter</button>
<br>
<hr>
List of students :
<p>- <b>Mark</b> has <b>Hobbies : </b> Climbing, Painting / <b>Attending Classes : </b>: <b>Art</b>, Geography</p>
<p>- <b>Jhon</b> has <b>Hobbies : </b> Climbing / <b>Attending Classes : </b> Art</p>
<p>- <b>Steven</b> has <b>Hobbies : </b> Climbing, Running / <b>Attending  Classes : </b> Art, Geography, Mathematics</p>

【问题讨论】:

  • 您将使用通过Include(或其他方式)加载,当在数据库上运行查询时,这将转换为JOIN
  • 我知道 Include 可以做到这一点,但我仍然不知道我将如何做我在问题中写的这个具体的事情。您有 ClassID 和 HobbyID,如果匹配,则获取 Student 对象以及他拥有的所有课程和爱好。
  • 如果您只想要学生,请在 Students 中执行查询,其中这些 ID 匹配。
  • (我还在学习)尝试去做但没有得到我想要的结果。如果你知道我会怎么做,你能写吗?

标签: c# asp.net-core entity-framework-core


【解决方案1】:

以下假设为 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; }
}

【讨论】:

  • 这不会把 Db 的所有学生都拉出来吗?假设您在 Hobby 表中有 20 行 Hobbies,而 Class 表中有相同数量的 Classes。您需要所有拥有 ID 为 5 和 ID 为 3 的爱好的学生,然后,学生对象需要在他在 DB 中拥有的所有班级和爱好中,而不仅仅是 ID 为 5 和 ID 为 3 的爱好。
  • 好的,所以您正在尝试构建一个具有所有课程和爱好选项的 Web 表单,但您还需要知道当前与学生相关联的课程和爱好?
  • 我在第一个查询中添加了 where 过滤器,以便它选择一个学生,因此也选择了学生当前的爱好和课程。然后我添加了两个简单的爱好和课程查询。从这里,您可以将这些数据放入模型类中,该模型类被馈送到剃刀视图中,该视图提供用于编辑学生课程和爱好的控件。
  • 您提到您不希望针对给定的学生爱好和课程多次查询数据库,这就是第一个查询完成的任务。如果您需要提供具有选择或多选框的 Web 表单,您需要在其中显示所有课程或爱好并选择当前选择的课程或爱好。
  • 我编辑了问题,添加了示例,现在可能会更清楚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 1970-01-01
  • 2022-12-09
  • 2021-12-22
  • 2018-02-21
  • 1970-01-01
相关资源
最近更新 更多