Entity Framework Core中SQL Server数据重复插入问题求助
Blazor EF Core 数据重复插入问题解决
问题描述
在Blazor+Entity Framework Core应用中,创建并保存关联了Transaction、TransactionDocument和TransactionItem的新数据时,所有数据会被SQL Server数据库重复插入两次,不符合预期。
相关代码
TransactionsCreate.razor(Razor页面)
@page "/TransactionsCreate" @using Aneta.Models @using Aneta.Data @code { [Inject] private DsaClusterContext? Context { get; set; } [Inject] private UnitOfWork? UnitOfWork { get; set; } private Transaction _transaction; private TransactionDocument _transactionDocument; private TransactionItem _transactionItem; protected override async Task OnInitializedAsync() { if (UnitOfWork == null || Context == null) return; try { // Create and configure the transaction _transaction = new Transaction { MunicipalityName = "Digos City", BarangayName = "Zone 3", }; // Create and configure the document _transactionDocument = new TransactionDocument { PunongBarangayName = "Aidre Cabrera", BarangayTreasurerName = "Trisha Talagtag" }; // Create and configure the item _transactionItem = new TransactionItem { Amount = 500, Cost = 58, Particulars = "Jasmine Rice", Price = 58, Quantity = 55, UnitName = "KG" }; // Establish the relationships _transaction.TransactionDocuments.Add(_transactionDocument); _transactionDocument.Transaction = _transaction; _transactionDocument.TransactionItems.Add(_transactionItem); _transactionItem.Document = _transactionDocument; // Start a unit of work and add the transaction to the repository UnitOfWork = new UnitOfWork(Context); UnitOfWork.Transaction.Add(_transaction); // Save all changes await UnitOfWork.CompleteAsync(); } catch (Exception ex) { // Handle exceptions as needed } finally { if (UnitOfWork != null) { UnitOfWork.Dispose(); } } } }
UnitOfWork类
using Aneta.Data.Repositories; using Aneta.Models; public class UnitOfWork : IUnitOfWork { private readonly DsaClusterContext? _context; public UnitOfWork(DsaClusterContext? context) { _context = context; Transaction = new SqlRepository<Transaction>(_context); TransactionDocuments = new SqlRepository<TransactionDocument>(_context); // Other repository initializations... } // Repository properties... public int Complete() { return _context!.SaveChanges(); } public async Task<int> CompleteAsync() { return await _context?.SaveChangesAsync()!; } public void Dispose() { _context?.Dispose(); } }
Transaction模型类
public partial class Transaction { public int TransactionId { get; set; } public string? MunicipalityName { get; set; } public string? BarangayName { get; set; } public virtual ICollection<TransactionDocument> TransactionDocuments { get; set; } = new List<TransactionDocument>(); }
TransactionDocument模型类
public partial class TransactionDocument { public int DocumentId { get; set; } public int? TransactionId { get; set; } public string? PunongBarangayName { get; set; } public string? BarangayTreasurerName { get; set; } public virtual ICollection<AbstractQuotation> AbstractQuotations { get; set; } = new List<AbstractQuotation>(); public virtual ICollection<PurchaseOrder> PurchaseOrders { get; set; } = new List<PurchaseOrder>(); public virtual ICollection<PurchaseRequest> PurchaseRequests { get; set; } = new List<PurchaseRequest>(); public virtual Transaction? Transaction { get; set; } public virtual ICollection<TransactionItem> TransactionItems { get; set; } = new List<TransactionItem>(); }
问题排查与解决方案
1. 核心原因:组件生命周期方法重复执行
Blazor组件的OnInitializedAsync方法在开发环境下(尤其是服务器端Blazor)可能因预渲染、热重载或组件重新渲染被执行多次,每次执行都会触发一次数据插入,导致重复数据。
2. 具体修复步骤
- 将插入逻辑移至用户触发事件:不要在
OnInitializedAsync中自动执行插入,改为通过按钮点击等用户交互触发,示例:<button @onclick="HandleCreateTransaction">创建交易</button> @code { private async Task HandleCreateTransaction() { // 原OnInitializedAsync中的插入逻辑移至此处 } } - 避免重复实例化UnitOfWork:已通过依赖注入获取
UnitOfWork实例,无需手动new UnitOfWork(Context),直接使用注入实例即可,减少上下文跟踪冲突:// 移除该行:UnitOfWork = new UnitOfWork(Context); UnitOfWork.Transaction.Add(_transaction); await UnitOfWork.CompleteAsync(); - 简化关联配置:EF Core会自动维护导航属性关联,无需同时设置双向关联,保留集合添加操作即可:
// 保留以下两行,移除另外两行赋值 _transaction.TransactionDocuments.Add(_transactionDocument); _transactionDocument.TransactionItems.Add(_transactionItem); - 检查DbContext生命周期:确保
DsaClusterContext在DI容器中配置为Scoped(Blazor推荐配置),避免单例上下文导致的共享跟踪问题:// Program.cs中的配置示例 builder.Services.AddDbContext<DsaClusterContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")), ServiceLifetime.Scoped);
环境信息
- EF Core版本:7.0.11
- 数据库提供程序:Microsoft.EntityFrameworkCore.SqlServer
- 目标框架:.NET 6.0
- 操作系统:Windows 11
- IDE:JetBrains Rider
内容的提问来源于stack exchange,提问作者Aidre Cabrera
相关产品推荐
相关产品推荐

