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; }
这是我的代码。
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; }