.NET Blazor Server带有EF编辑表单,管理取消并提交
我有很长一段时间以来与Blazor Serds遇到的问题。我有一个EF模型的编辑表格,但我无法弄清楚如何处理取消。这是我的代码:
@inject NavigationManager nav
<h3>Edit @_tmpCustomer.FullName</h3>
<EditForm Model=@_tmpCustomer>
<DataAnnotationsValidator/>
<ValidationSummary/>
<label>First Name</label>
<InputText @bind-Value=_tmpCustomer.FName/>
<br/>
<label>Last Name</label>
<InputText @bind-Value=_tmpCustomer.LName/>
<br/>
<label>Phone Number</label>
<InputText @bind-Value=_tmpCustomer.PhoneNumber/>
<br/>
<button class="btn btn-primary" @onclick=UpdateCustomer>Save</button>
<button class="btn btn-primary" @onclick=@(() => NavTo("/customers"))> Cancel</button>
</EditForm>
@code {
[Parameter]
public int customerId { get; set; }
private Customer _customer { get; set; }
private Customer _tmpCustomer { get; set; }
protected override async Task OnInitializedAsync()
{
await LoadCustomer(customerId);
}
private async Task LoadCustomer(int customerId)
{
_customer = await _customerRepo.GetCustomerFromId(customerId);
_tmpCustomer = (Customer)_customer.Clone();
}
private async Task UpdateCustomer()
{
_customer = _tmpCustomer;
await _customerRepo.Update(_customer);
await NavTo("/customers");
}
private async Task NavTo(string uri)
{
nav.NavigateTo(uri);
}
}
public class Customer
{
...
public virtual object Clone()
{
return this.MemberwiseClone
}
}
public class CustomerRepo
{
private ApplicationDbContext _context;
public CustomerRepo(ApplicationDbContext context)
{
_context = context;
}
public async Task<List<Customer>> GetAllCustomers()
{
return _context.Customers.ToList();
}
public async Task<Customer> GetCustomerFromId(int customerId)
{
return _context.Customers.FirstOrDefault(c => c.Id == customerId);
}
public async Task Create(Customer customer)
{
_context.Add(customer);
await _context.SaveChangesAsync();
}
public async Task Update(Customer customer)
{
_context.Update(customer);
await _context.SaveChangesAsync();
}
}
问题是我不能同时跟踪同一EF模型的两个实例,我可以分离它,但我认为这不是这样做的干净或正确的方法。
在Blazor Server中取消编辑表格的正确方法是什么?
谢谢 :)
I have a problem that I have had with blazor server side for a long time. I have an edit form for an EF model but I cannot figure out how to handle cancelation. This is my code:
@inject NavigationManager nav
<h3>Edit @_tmpCustomer.FullName</h3>
<EditForm Model=@_tmpCustomer>
<DataAnnotationsValidator/>
<ValidationSummary/>
<label>First Name</label>
<InputText @bind-Value=_tmpCustomer.FName/>
<br/>
<label>Last Name</label>
<InputText @bind-Value=_tmpCustomer.LName/>
<br/>
<label>Phone Number</label>
<InputText @bind-Value=_tmpCustomer.PhoneNumber/>
<br/>
<button class="btn btn-primary" @onclick=UpdateCustomer>Save</button>
<button class="btn btn-primary" @onclick=@(() => NavTo("/customers"))> Cancel</button>
</EditForm>
@code {
[Parameter]
public int customerId { get; set; }
private Customer _customer { get; set; }
private Customer _tmpCustomer { get; set; }
protected override async Task OnInitializedAsync()
{
await LoadCustomer(customerId);
}
private async Task LoadCustomer(int customerId)
{
_customer = await _customerRepo.GetCustomerFromId(customerId);
_tmpCustomer = (Customer)_customer.Clone();
}
private async Task UpdateCustomer()
{
_customer = _tmpCustomer;
await _customerRepo.Update(_customer);
await NavTo("/customers");
}
private async Task NavTo(string uri)
{
nav.NavigateTo(uri);
}
}
public class Customer
{
...
public virtual object Clone()
{
return this.MemberwiseClone
}
}
public class CustomerRepo
{
private ApplicationDbContext _context;
public CustomerRepo(ApplicationDbContext context)
{
_context = context;
}
public async Task<List<Customer>> GetAllCustomers()
{
return _context.Customers.ToList();
}
public async Task<Customer> GetCustomerFromId(int customerId)
{
return _context.Customers.FirstOrDefault(c => c.Id == customerId);
}
public async Task Create(Customer customer)
{
_context.Add(customer);
await _context.SaveChangesAsync();
}
public async Task Update(Customer customer)
{
_context.Update(customer);
await _context.SaveChangesAsync();
}
}
The problem is that I cannot have 2 instances of the same EF model tracked at the same time, I could detach it but I don't think that's the clean or right way to do this.
What would be the correct way to cancel an edit form in blazor server?
Thanks :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题在于整个用户会话都使用相同的DBContext。这在数据库访问 Blazor Server和EF Core 文档。您必须自己管理DBContext的一生。
文档示例显示了注册DBContextFactory的注册:
这类似于您在AddDbContext中使用的内容。
然后,该页面注入dbContextFactory而不是实际的dbcontext,并在
onInitialized
中创建一个新的dbContext实例该页面必须实现
idisposable
,因此它可以派遣上下文实例远离页面时:
说明
在Web应用程序中,依赖项注入范围是控制器操作,这意味着当完成新操作并在完成时执行并处理新操作时,创建了范围范围的服务。这与DBContext的“工作单元”语义很好,因为更改仅用于单个动作。 “取消”是指根本不调用
savechanges
。Blazor Server的行为就像桌面应用程序一样,范围是整个用户电路(将其视为用户会话)。您必须为每个工作单元创建一个新的DBContext。
做到这一点的一种方法是显式创建一个新的dbcontext,即
new ApplicationDbContext()
。这有效,但需要对配置进行硬编码。另一个选项是将DBContextFactory而不是
applicationdbcontext
注入custome> customerrepo
或页面,并根据需要创建DBContext实例。请注意,customerrepo
本身现在已经为整个用户会话而活,因此您不能仅仅用DBContext的包装器来依靠它。The problem is that the same DbContext is used for the entire user session. This is explained in the Database Access section of the Blazor Server and EF Core docs. You'll have to manage the DbContext's lifetime yourself.
The documentation example shows registering a DbContextFactory with :
Which is similar to what you'd use with AddDbContext.
Then the page injects the DbContextFactory instead of the actual DbContext and creates a new DbContext instance in
OnInitialized
The page has to implement
IDisposable
so it can dispoce theContext
instance when you navigate away from the page:Explanation
In web applications the Dependency Injection scope is the controller action, which means scoped services are created when a new action is executed and disposed when it completes. This works nicely with DbContext's Unit-of-Work semantics, as changes are cached only for a single action. "Cancelling" means simply not calling
SaveChanges
.Blazor Server behaves like a desktop application though, and the scope is the entire user circuit (think of it as a user session). You'll have to create a new DbContext for each unit of work.
One way to do this is to just create a new DbContext explicitly, ie
new ApplicationDbContext()
. This works but requires hard-coding the configuration.Another option is to inject a DbContextFactory instead of the
ApplicationDbContext
into yourCustomerRepo
or page, and create the DbContext instance as needed. Note thatCustomerRepo
itself is now alive for the entire user session, so you can't depend on it working as just a wrapper over DbContext.我做以下操作:
取消编辑很简单,您无法保存!
首先更改为使用dbContextFactory。 MSSQL看起来像这样:
并更新您的客户存储库以使用此功能。
创建
方法现在变为:将客户更改为记录
为客户创建编辑类
,然后您的编辑表格可以看起来像这样:
我实际上没有运行代码,因此可能会有一些错别字呢
I do the following:
Canceling the edit is then simple, you don't save!
First change over to using the DBContextFactory. The MSSQL one looks like this:
And update your Customer Repo to use this.
And the
Create
method now becomes:Change Customer to a record
Create an edit class for Customer
And then your edit form can look something like this:
I haven't actually run the code so there may be some typos!