我有一个带有 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 的正确方法是什么?
在 Blazor 项目中使用 EF Core 的正确方法是什么?
不要将 DbContext 实例注入组件中。它的寿命是短暂的,而你的组件却是长寿的。
相反,在每个事件回调中注入
IDbContextFactory<TDbContext>
。
请参阅有关该主题的官方文档:https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-ef-core?view=aspnetcore-8.0