ASP.NET MVC Parent-Child 与 ViewModel 和 Entity Framework

ASP.NET MVC Parent-Child with ViewModel and Entity Framework

这是我的代码。

Parent:

public class Parent
{
    [Key]
    public int Id { get; set; }

    [Required]
    [MaxLength(50), MinLength(3)]
    [Display(Name = "Parent Name")]
    public string Name { get; set; }

    [Required]
    [MaxLength(50), MinLength(3)]
    [Display(Name = "Parent Surname")]
    public string Surname { get; set; }

    public List<Child> Children { get; set; } = new List<Child>();
}

Child:

public class Child
{
    [Key]
    public int Id { get; set; }

    [Required]
    [MaxLength(50), MinLength(3)]
    [Display(Name = "Child Name")]
    public string Name { get; set; }

    [Required]
    [MaxLength(50), MinLength(3)]
    [Display(Name = "Child Surname")]
    public string Surname { get; set; }

    [Required]
    [Display(Name = "Parent")]
    public int ParentId { get; set; }

    [ForeignKey("ParentId")]
    public virtual Parent Parent { get; set; }
}

视图模型:

public class ParentChildViewModel
{
    public Parent Parent { get; set; }
    public IEnumerable<Child> Children { get; set; }
}

控制器:

public class DemoController : Controller
{
    private readonly ApplicationDbContext _db;
    public DemoController(ApplicationDbContext db)
    {
        _db = db;
    }
    public async Task<IActionResult> Index(int id)
    {
        var parent = await _db.Parents.AsNoTracking().FirstOrDefaultAsync(i => i.Id == id);

        var child = await _db.Children.AsNoTracking().Where(i => i.ParentId == id).ToListAsync();
        
        var model = new ParentChildViewModel
        {
            Parent = parent,
            Children = child
        };

        return View(model);
    }
}

查看:

@model TwoModels.Models.ParentChildViewModel
<h2> Demo Table Parent</h2>
<table style="border:solid 2px;">
    <tr>
        <td>
            Parent Name:
        </td>
        <td>
            @Html.DisplayFor(m => m.Parent.Name) <br />
        </td>
    </tr>
    <tr>
        <td>
            Parent Surname:
        </td>
        <td>
            @Html.DisplayFor(m => m.Parent.Surname) <br />
        </td>
    </tr>
</table>
<h2>Demo Table Child</h2>
<table style="border:solid 2px;">
    @foreach (var item in Model.Children)
    {
        <tr>
            <td>
                Child Name:
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Name) <br />
            </td>
        </tr>
        <tr>
            <td>
                Child Surname:
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Surname) <br />
            </td>
        </tr>
    }
</table>

代码很容易理解,我使用: _db.Parents.AsNoTracking().FirstOrDefaultAsync(i => i.Id == id) for Parent(我不想要列表,只想要第一个) 和: _db.Children.AsNoTracking().Where(i => i.ParentId == id).ToListAsync()(这是一个列表)

但是这样就向数据库请求了两次。所以,我想修改代码,保留 ViewModel 的使用,但只访问数据库一次。我想到了什么:

_db.Parents.AsNoTracking().Include(c=>c.Children).Where(i => i.Id == id).ToListAsync();

如何更改控制器代码和视图?

你的动作可能是这样的:

public async Task<IActionResult> Index(int id)
    {
        var item = await _db.Parents.AsNoTracking().
.Include(c=>c.Children)
.Where(i => i.Id == id).
FirstOrDefaultAsync();

           var model = new ParentChildViewModel
        {
            Parent = item,
            Children = item.Children
        };
         item.Children=null; // only if you want to use view model alone.
        return View(model);
    }

并从子 属性 中删除新的 List()。应该是这样的:

public List<Child> Children { get; set; }