StateHasChanged 未在 Blazor Web App 中正确更新 - 如何使用 EF Core?

问题描述 投票:0回答:1

我有一个带有 InteractiveServer 渲染模式的 blazor Web 应用程序。我有一个带有 SignalR 集线器的编辑页面,当其他人编辑该对象时,该集线器必须刷新该对象。以下代码位于我的 Razor 页面中:

@page "/Projects/edit"
@inject BlazorApp2.Data.ApplicationDbContext DB
@using BlazorApp2.Data.Models
@inject NavigationManager NavigationManager
@using Microsoft.AspNetCore.SignalR.Client
@using Microsoft.EntityFrameworkCore
@rendermode InteractiveServer

<PageTitle>Edit</PageTitle>

@if (Project is null)
{
    <p><em>Loading...</em></p>
}
else
{
    <div class="row">
        <div class="col-md-4">
            <EditForm method="post" Model="Project" OnValidSubmit="UpdateProject" FormName="edit" Enhance>
                <DataAnnotationsValidator />
                <ValidationSummary />
                <input type="hidden" name="Project.Id" value="@Project.Id" />
                <div class="mb-3">
                    <label for="name" class="form-label">Name:</label>
                    <InputText id="name" @bind-Value="Project.Name" class="form-control" />
                    <ValidationMessage For="() => Project.Name" class="text-danger" />
                </div>

                @if (Project.Subjects is object)
                {
                    @foreach (var subject in Project.Subjects)
                    {
                        <div class="mb-3">
                            <label for="subject" class="form-label">Name:</label>
                            <InputText id="subject" @bind-Value="subject.Name" class="form-control" />
                            <ValidationMessage For="() => subject.Name" class="text-danger" />
                        </div>
                        <div @onclick="() => RemoveSubject(subject)">REMOVE</div>
                    }
                }

                @if (Orders is object)
                {
                    @foreach (var order in Orders)
                    {
                        <input checked="@((Project.Orders is object && Project.Orders.Any(x => x.Id == order.Id)) ? true : false)" @onchange="eventArgs => OrderClicked(order, eventArgs.Value)" type="checkbox" class="custom-control-input"></input>
                        <label class="custom-control-label">@(order.Name)</label>
                        <br />
                    }
                }

                <button type="submit" class="btn btn-primary">Save</button>
            </EditForm>
            <button type="button" @onclick="NewSubject" class="btn btn-primary">+ Subject</button>
            <h1>@(Testtest)</h1>
        </div>
    </div>
}

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

@code {
    [SupplyParameterFromQuery]
    public int Id { get; set; }

    public Project Project = new();
    private List<Order> Orders = new();

    private EditContext _editContext;
    private HubConnection _hub;
    private string Testtest = "";

    protected override async Task OnInitializedAsync()
    {
        Project = await DB.Project.Include(x => x.Subjects).Include(x => x.Orders).FirstOrDefaultAsync(m => m.Id == Id);
        Orders = await DB.Order.ToListAsync();

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

        _hub = new HubConnectionBuilder()
                .WithUrl(NavigationManager.ToAbsoluteUri("/dmhub"))
                .Build();

        _hub.On<string, int>("CUD", (Model, Id) =>
        {

            if (Model == "debtor" && Id == Id)
            {
                InvokeAsync(() => RefreshData());
            }

        });

        await _hub.StartAsync();

    }

    private async Task RefreshData()
    {
        Project = await DB.Project.Include(x => x.Subjects).Include(x => x.Orders).FirstOrDefaultAsync(m => m.Id == Id);
        await InvokeAsync(StateHasChanged);
    }

    public async Task UpdateProject()
    {
        DB.Attach(Project).State = EntityState.Modified;

        try
        {
            await DB.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!ProjectExists(Project!.Id))
            {
                NavigationManager.NavigateTo("notfound");
            }
            else
            {
                throw;
            }
        }
        await _hub.SendAsync("CUD", "debtor", Project.Id);
        NavigationManager.NavigateTo("/projects");
    }

    bool ProjectExists(int id)
    {
        return DB.Project.Any(e => e.Id == id);
    }

    private void NewSubject()
    {
        if (Project.Subjects is not object)
        {
            Project.Subjects = new();
        }
        Project.Subjects.Add(new Subject());
    }

    private void RemoveSubject(Subject subject)
    {
        if (Project.Subjects is not object)
        {
            Project.Subjects = new();
        }
        Project.Subjects.Remove(subject);
    }

    public void OrderClicked(Order order, object checkValue)
    {

        if (Project.Orders is not object)
        {
            Project.Orders = new();
        }

        if ((bool)checkValue == true)
        {
            if (!Project.Orders.Any(x => x.Id == order.Id))
            {
                Project.Orders.Add(order);
            }
        }
        else
        {
            if (Project.Orders.Any(x => x.Id == order.Id))
            {
                Project.Orders.RemoveAll(s => s.Id == order.Id);
            }
        }
    }
}

每当我向浏览器选项卡 1 中的

Order
添加新的
Subject
Project
时,这会立即显示在浏览器选项卡 2 中。但是每当我删除一个或更改项目名称时,这都不会显示在浏览器选项卡 2 中,除非我按 F5。

我尝试更改为以下代码:

IDbContextFactory<BlazorApp2.Data.ApplicationDbContext> _context

private async Task RefreshData()
{
    using (var _db = _context.CreateDbContext())
    {
        Project = await _db.Project.Include(x => x.Subjects).Include(x => x.Orders).FirstOrDefaultAsync(m => m.Id == Id);
        await InvokeAsync(StateHasChanged);
    }
}

public async Task UpdateProject()
{
    using (var _db = _context.CreateDbContext())
    {
        _db.Attach(Project).State = EntityState.Modified;
        try
        {
            await DB.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!ProjectExists(Project!.Id))
            {
                NavigationManager.NavigateTo("notfound");
            }
            else
            {
                throw;
            }
        }
        await _hub.SendAsync("CUD", "debtor", Project.Id);
        NavigationManager.NavigateTo("/projects");
    }
}

但是每当我使用此代码时,项目都无法正确保存。添加的订单或主题不会保存到数据库中。 EF Core 不会以这种方式看到对对象所做的更改。

在 Blazor 项目中使用 EF Core 的正确方法是什么?

c# entity-framework-core blazor blazor-server-side
1个回答
0
投票

在 Blazor 项目中使用 EF Core 的正确方法是什么?

不要将 DbContext 实例注入组件中。它的寿命是短暂的,而你的组件却是长寿的。

相反,在每个事件回调中注入

IDbContextFactory<TDbContext>

请参阅有关该主题的官方文档:https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-ef-core?view=aspnetcore-8.0

© www.soinside.com 2019 - 2024. All rights reserved.