Обновление связанных объектов - PullRequest
0 голосов
/ 19 ноября 2018

AppUser идентификационная модель:

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

Используя Razor Pages, я вызываю частичное представление, например:

@await Html.PartialAsync("_NameAndID", Model.AppUser)

PageModel:

[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<IActionResult> OnPostAsync() соответствующий AppUser.UserPhones равен null. ( проблема )

Вы можете помочь?

Заранее спасибо !!!!

1 Ответ

0 голосов
/ 20 ноября 2018

Причина

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, при публикации на сервере полезная нагрузка будет:

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<UserPhones>, чтобы мы могли использовать синтаксис индекса

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 будет правильно установлено. Вот скриншот демо:

enter image description here

...