更新相关实体
Updating related entities
AppUser
身份模型:
public virtual ICollection<UserPhones> UserPhones { get; set; }
使用 Razor Pages,我调用局部视图,如下所示:
@await Html.PartialAsync("_NameAndID", Model.AppUser)
页面模型:
[BindProperty]
public AppUser AppUser { get; set; }
public IActionResult OnGet()
{
AppUser = _userManager.Users
//.Include(x => x.UserAddresses) //OMITTED BC USING LAZY LOADING
.SingleOrDefaultAsync(x => x.UserName ==
_httpContext.HttpContext.User.Identity.Name).Result;
return Page();
}
在 _NameAndID.cshtml
中,我明确引用了来自 UserPhones
实体的特定 telephone。有:
<input type="hidden" asp-for="UserPhones
.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).UserPhoneId" />
//other properties removed for brevity
<div class="rvt-grid__item">
<label asp-for="UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber">Mobile Phone</label>
<input asp-for="UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber" autocomplete="tel" />
<span asp-validation-for="UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber"></span>
</div>
在运行时,显式移动 phone 号码已正确加载。但是,当发布到 public async Task<IActionResult> OnPostAsync()
时,相关的 AppUser.UserPhones
是 null
。 (问题)
你能帮忙吗?
提前致谢!!!
原因
asp-for
不适用于这种情况。
考虑您在 _NameAndID.cshtml
中的代码:
<input asp-for="UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber" autocomplete="tel" />
注意此处的 LINQ 扩展方法 .SingleOrDefault(...)
。 这里的asp-for
不知道如何得到UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber
的名字,所以直接渲染成PhoneNumber
。结果,呈现的 html 将是:
<input autocomplete="tel" type="text" id="PhoneNumber" name="PhoneNumber" value="">
假设有人输入值 911
,当 post 发送到服务器时,有效负载将为:
PhoneNumber=911
因为您在服务器端的页面模型是:
[BindProperty]
public AppUser AppUser{get;set;}
public IActionResult OnGet()
{
// ...
}
public IActionResult OnPostAsync()
{
return Page();
}
注意 AppUser.UserPhones
属性 是一个集合。换句话说,AppUser
需要一个像这样的有效负载:
UserPhones[0].UserPhoneId=1&UserPhones[0].PhoneNumber=911&UserPhones[1].UserPhoneId=2&UserPhones[1].PhoneNumber=119
但是,您发送到服务器的是:
PhoneNumber=911
因此 App.UserPhones
将始终为 null 而 AppUser.PhoneNumber
属性 将是 911
.
如何修复
首先,为了自动绑定 UserPhones
,我将 App.UserPhones
的类型更改为 IList<UserPhones>
,这样我们就可以使用索引语法
public class AppUser : IdentityUser{
// public virtual ICollection<UserPhones> UserPhones { get; set; }
public virtual IList<UserPhones> UserPhones { get; set; }
}
其次,不要在asp-for
中使用复杂的查询,而是使用简单的索引语法。比如你想post一些UserPhones
或者post全部UserPhones
,你可以为每个字段添加一个索引:
@for(var i=0;i <Model.UserPhones.Count(); i++) {
<div class="rvt-grid__item">
<label asp-for="@Model.UserPhones[i].UserPhoneId"></label>
<input asp-for="@Model.UserPhones[i].UserPhoneId"/>
<label asp-for="@Model.UserPhones[i].PhoneNumber"></label>
<input asp-for="@Model.UserPhones[i].PhoneNumber"/>
<span asp-validation-for="@Model.UserPhones[i].PhoneNumber"></span>
</div>
}
这样,当有人提交表单时,AppUser.UserPhones
将是正确的设置。这是演示的屏幕截图:
AppUser
身份模型:
public virtual ICollection<UserPhones> UserPhones { get; set; }
使用 Razor Pages,我调用局部视图,如下所示:
@await Html.PartialAsync("_NameAndID", Model.AppUser)
页面模型:
[BindProperty]
public AppUser AppUser { get; set; }
public IActionResult OnGet()
{
AppUser = _userManager.Users
//.Include(x => x.UserAddresses) //OMITTED BC USING LAZY LOADING
.SingleOrDefaultAsync(x => x.UserName ==
_httpContext.HttpContext.User.Identity.Name).Result;
return Page();
}
在 _NameAndID.cshtml
中,我明确引用了来自 UserPhones
实体的特定 telephone。有:
<input type="hidden" asp-for="UserPhones
.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).UserPhoneId" />
//other properties removed for brevity
<div class="rvt-grid__item">
<label asp-for="UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber">Mobile Phone</label>
<input asp-for="UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber" autocomplete="tel" />
<span asp-validation-for="UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber"></span>
</div>
在运行时,显式移动 phone 号码已正确加载。但是,当发布到 public async Task<IActionResult> OnPostAsync()
时,相关的 AppUser.UserPhones
是 null
。 (问题)
你能帮忙吗?
提前致谢!!!
原因
asp-for
不适用于这种情况。
考虑您在 _NameAndID.cshtml
中的代码:
<input asp-for="UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber" autocomplete="tel" />
注意此处的 LINQ 扩展方法 .SingleOrDefault(...)
。 这里的asp-for
不知道如何得到UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber
的名字,所以直接渲染成PhoneNumber
。结果,呈现的 html 将是:
<input autocomplete="tel" type="text" id="PhoneNumber" name="PhoneNumber" value="">
假设有人输入值 911
,当 post 发送到服务器时,有效负载将为:
PhoneNumber=911
因为您在服务器端的页面模型是:
[BindProperty]
public AppUser AppUser{get;set;}
public IActionResult OnGet()
{
// ...
}
public IActionResult OnPostAsync()
{
return Page();
}
注意 AppUser.UserPhones
属性 是一个集合。换句话说,AppUser
需要一个像这样的有效负载:
UserPhones[0].UserPhoneId=1&UserPhones[0].PhoneNumber=911&UserPhones[1].UserPhoneId=2&UserPhones[1].PhoneNumber=119
但是,您发送到服务器的是:
PhoneNumber=911
因此 App.UserPhones
将始终为 null 而 AppUser.PhoneNumber
属性 将是 911
.
如何修复
首先,为了自动绑定 UserPhones
,我将 App.UserPhones
的类型更改为 IList<UserPhones>
,这样我们就可以使用索引语法
public class AppUser : IdentityUser{
// public virtual ICollection<UserPhones> UserPhones { get; set; }
public virtual IList<UserPhones> UserPhones { get; set; }
}
其次,不要在asp-for
中使用复杂的查询,而是使用简单的索引语法。比如你想post一些UserPhones
或者post全部UserPhones
,你可以为每个字段添加一个索引:
@for(var i=0;i <Model.UserPhones.Count(); i++) {
<div class="rvt-grid__item">
<label asp-for="@Model.UserPhones[i].UserPhoneId"></label>
<input asp-for="@Model.UserPhones[i].UserPhoneId"/>
<label asp-for="@Model.UserPhones[i].PhoneNumber"></label>
<input asp-for="@Model.UserPhones[i].PhoneNumber"/>
<span asp-validation-for="@Model.UserPhones[i].PhoneNumber"></span>
</div>
}
这样,当有人提交表单时,AppUser.UserPhones
将是正确的设置。这是演示的屏幕截图: