【问题标题】:Updating related entities更新相关实体
【发布时间】:2019-04-22 03:21:45
【问题描述】:

AppUser身份模型:

public virtual ICollection<UserPhones> UserPhones { get; set; }

使用 Razor 页面,我称之为局部视图,如下所示:

@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 实体的特定电话。与:

<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>

在运行时,正确加载显式手机号码。但是,当发布到public async Task&lt;IActionResult&gt; OnPostAsync() 时,相关的AppUser.UserPhonesnull。 (问题

你能帮忙吗?

提前谢谢你!!!!

【问题讨论】:

    标签: entity-framework asp.net-core partial-views razor-pages


    【解决方案1】:

    原因

    asp-for 不适用于这种情况。

    考虑您在_NameAndID.cshtml 中的代码:

    <input asp-for="UserPhones.SingleOrDefault(z => z.Type == EnumPhoneType.Mobile).PhoneNumber" autocomplete="tel" />
    

    请注意此处的 LINQ 扩展方法.SingleOrDefault(...)这里的asp-for不知道如何获取UserPhones.SingleOrDefault(z =&gt; z.Type == EnumPhoneType.Mobile).PhoneNumber的名字,所以直接渲染为PhoneNumber。结果,呈现的 html 将是:

    <input autocomplete="tel" type="text" id="PhoneNumber" name="PhoneNumber" value="">
    

    假设有人输入了911的值,当发布到服务器时,有效负载将为:

    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 将始终为空,AppUser.PhoneNumber 属性将为911

    如何修复

    首先,为了自动绑定UserPhones,我将App.UserPhones的类型改为IList&lt;UserPhones&gt;,这样我们就可以使用索引语法了

    public class AppUser : IdentityUser{
    
        // public virtual ICollection<UserPhones> UserPhones { get; set; }
        public virtual IList<UserPhones> UserPhones { get; set; }
    
    }
    

    其次,不要在asp-for中使用复杂的查询,而是使用简单的索引语法。例如,如果您想发布一些UserPhones 或发布所有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 将被正确设置。这是演示的截图:

    【讨论】:

    • 谢谢@itminus!这正是我昨天最终做的事情,它就像一个冠军。考虑转换为标签助手,以便我可以在需要编辑电话号码的整个应用程序中使其可重用。再次感谢!
    • 您好@itminus,如果您也有兴趣提供帮助,我发布了自定义标签助手的想法。如果没有,不用担心。再次感谢。见:stackoverflow.com/questions/53395905/complex-custom-tag-helper
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多