You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor中InputSelect提交后值重置问题求助

问题解决方法

核心问题及修复步骤

1. 移除InputSelect中手动设置的selected属性

Blazor的@bind-Value会自动管理下拉框的选中状态,手动添加selected会干扰双向绑定逻辑,导致选择的新值无法正确同步到绑定属性。

原代码片段:

@if (movieStarRating.Id == Movie.MovieStarRatingId)
{
    <option value="@movieStarRating.Id" selected>@movieStarRating.Descr</option>
}
else
{
    <option value="@movieStarRating.Id">@movieStarRating.Descr</option>
}

修改后:

<option value="@movieStarRating.Id">@movieStarRating.Descr</option>

2. 移除Movie属性上的[SupplyParameterFromForm]特性

在交互式服务器组件中,该特性会在表单提交时尝试从表单数据重新绑定Movie对象,覆盖你在组件中修改后的实例,直接导致值被重置回初始状态。

原代码:

[SupplyParameterFromForm]
private Movie? Movie { get; set; }

修改后:

private Movie? Movie { get; set; }

3. 修正ValidationMessage的绑定目标

当前ValidationMessage指向Movie.MovieStarRating,但实际绑定的是MovieStarRatingId,需要调整表达式指向正确的属性:

原代码:

<ValidationMessage For="() => Movie.MovieStarRating" class="text-danger"></ValidationMessage>

修改后:

<ValidationMessage For="() => Movie.MovieStarRatingId" class="text-danger"></ValidationMessage>

4. 优化EF Core的更新逻辑(可选但推荐)

直接使用Attach并设置EntityState.Modified可能引发并发问题,建议先从数据库获取最新实体,再更新需要修改的属性,同时避免过度提交风险:

原UpdateMovie方法:

private async Task UpdateMovie()
{
    using var context = DbFactory.CreateDbContext();
    context.Attach(Movie!).State = EntityState.Modified;

    try
    {
        await context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!MovieExists(Movie!.Id))
        {
            NavigationManager.NavigateTo("notfound");
        }
        else
        {
            throw;
        }
    }

    NavigationManager.NavigateTo("/movies");
}

修改后:

private async Task UpdateMovie()
{
    using var context = DbFactory.CreateDbContext();
    var existingMovie = await context.Movie.FirstOrDefaultAsync(m => m.Id == Movie!.Id);
    
    if (existingMovie == null)
    {
        NavigationManager.NavigateTo("notfound");
        return;
    }

    // 手动更新需要修改的属性,避免过度提交
    existingMovie.Title = Movie.Title;
    existingMovie.ReleaseDate = Movie.ReleaseDate;
    existingMovie.Genre = Movie.Genre;
    existingMovie.Price = Movie.Price;
    existingMovie.Rating = Movie.Rating;
    existingMovie.MovieStarRatingId = Movie.MovieStarRatingId;

    try
    {
        await context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!MovieExists(Movie.Id))
        {
            NavigationManager.NavigateTo("notfound");
        }
        else
        {
            throw;
        }
    }

    NavigationManager.NavigateTo("/movies");
}

完整修正后的代码

@page "/movies/edit"
@rendermode InteractiveServer
@using Microsoft.EntityFrameworkCore
@using BlazorWebAppMovies.Models
@using BlazorWebAppMovies.Data
@inject IDbContextFactory<BlazorWebAppMovies.Data.BlazorWebAppMoviesContext> DbFactory
@inject NavigationManager NavigationManager

<PageTitle>Edit</PageTitle>

<h1>Edit</h1>

<h2>Movie</h2>
<hr />
@if (Movie is null)
{
    <p><em>Loading...</em></p>
}
else
{
    <div class="row">
        <div class="col-md-4">
            <EditForm Model="Movie" OnValidSubmit="UpdateMovie" FormName="edit" Enhance>
                <DataAnnotationsValidator />
                <ValidationSummary role="alert"/>
                <input type="hidden" name="Movie.Id" value="@Movie.Id" />
                <div class="mb-3">
                    <label for="title" class="form-label">Title:</label>
                    <InputText id="title" @bind-Value="Movie.Title" class="form-control" />
                    <ValidationMessage For="() => Movie.Title" class="text-danger" />
                </div>
                <div class="mb-3">
                    <label for="releasedate" class="form-label">Release Date:</label>
                    <InputDate id="releasedate" @bind-Value="Movie.ReleaseDate" class="form-control" />
                    <ValidationMessage For="() => Movie.ReleaseDate" class="text-danger" />
                </div>
                <div class="mb-3">
                    <label for="genre" class="form-label">Genre:</label>
                    <InputText id="genre" @bind-Value="Movie.Genre" class="form-control" />
                    <ValidationMessage For="() => Movie.Genre" class="text-danger" />
                </div>
                <div class="mb-3">
                    <label for="price" class="form-label">Price:</label>
                    <InputNumber id="price" @bind-Value="Movie.Price" class="form-control" />
                    <ValidationMessage For="() => Movie.Price" class="text-danger" />
                </div>
                <div class="mb-3">
                    <label for="rating" class="form-label">Rating:</label>
                    <InputText id="rating" @bind-Value="Movie.Rating" class="form-control" />
                    <ValidationMessage For="() => Movie.Rating" class="text-danger" />
                </div>
                <div class="mb-3">
                    <label for="moviestarrating" class="form-label">Movie Star Rating:</label>
                    <InputSelect id="moviestarrating" @bind-Value="Movie.MovieStarRatingId" class="form-control">
                        @foreach (var movieStarRating in StarRatings)
                        {
                            @if (movieStarRating.Id != 0)
                            {
                                <option value="@movieStarRating.Id">@movieStarRating.Descr</option>
                            }                           
                        }
                    </InputSelect>
                    <ValidationMessage For="() => Movie.MovieStarRatingId" class="text-danger"></ValidationMessage>
                </div>
                <button type="submit" class="btn btn-primary">Save</button>
            </EditForm>
        </div>
    </div>
}

<div>
    <a href="/movies">Back to List</a>
</div>

@code {
    private BlazorWebAppMoviesContext context = default!;

    [SupplyParameterFromQuery]
    private int Id { get; set; }

    private Movie? Movie { get; set; }

    private IList<MovieStarRating> StarRatings { get; set; } = [];

    protected override async Task OnInitializedAsync()
    {
        using var context = DbFactory.CreateDbContext();
        Movie ??= await context.Movie.FirstOrDefaultAsync(m => m.Id == Id);

        if (Movie is null)
        {
            NavigationManager.NavigateTo("notfound");
        }

        StarRatings = await context.MovieStarRating.ToListAsync();
    }

    // To protect from overposting attacks, enable the specific properties you want to bind to.
    private async Task UpdateMovie()
    {
        using var context = DbFactory.CreateDbContext();
        var existingMovie = await context.Movie.FirstOrDefaultAsync(m => m.Id == Movie!.Id);
        
        if (existingMovie == null)
        {
            NavigationManager.NavigateTo("notfound");
            return;
        }

        // 更新指定属性,避免过度提交
        existingMovie.Title = Movie.Title;
        existingMovie.ReleaseDate = Movie.ReleaseDate;
        existingMovie.Genre = Movie.Genre;
        existingMovie.Price = Movie.Price;
        existingMovie.Rating = Movie.Rating;
        existingMovie.MovieStarRatingId = Movie.MovieStarRatingId;

        try
        {
            await context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(Movie.Id))
            {
                NavigationManager.NavigateTo("notfound");
            }
            else
            {
                throw;
            }
        }

        NavigationManager.NavigateTo("/movies");
    }

    private bool MovieExists(int id)
    {
        using var context = DbFactory.CreateDbContext();
        return context.Movie.Any(e => e.Id == id);
    }
}

内容的提问来源于stack exchange,提问作者Rusty0918-B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:25:53