我遇到了一个非常奇怪的错误,非常感谢您的帮助。我目前正在使用.net7 开发一个新的winforms 应用程序。我们正在使用 EF core 与 MS Acces DB 文件集成(别无选择)。我构建了一个查询现有 BusinessDate 实体对象的服务,然后向其中添加子 OtcVariationMarginRecords。我一直在单元和集成测试(XUnit)中专门致力于此。在集成测试中,我遇到了一个问题:直到几天前,该服务都完美运行,将所有记录按预期保存在数据库文件中。然后两天前,我开始收到这个错误:
System.InvalidOperationException:无法跟踪实体类型“OtcVariationMarginRecord”的实例,因为已跟踪具有相同键值 {'Id'} 的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看冲突的键值。
我尝试过的:
我感到完全被难住了,希望这里有人能指出我的代码中的明显缺陷。非常感谢。
实体模型:
[Index(nameof(Date), IsUnique = true)]
public class BusinessDate : BaseEntity
{
public DateTime Date { get; set; }
public List<OtcVariationMarginRecord> OtcVariationMarginRecords { get; set; } = new();
}
public class OtcVariationMarginRecord : BaseEntity
{
public decimal BaseCurrencyExposure { get; set; }
public CurrencyCode BaseCurrency { get; set; }
public decimal TransferAmount { get; set; }
public MarginCallNature CallNature { get; set; }
public MarginDirection Direction { get; set; }
public decimal RoundedTransferAmount { get; set; }
// i have removed a bunch of properties as part of my trouble shooting.
}
public abstract class BaseEntity : IBaseEntity
{
[Key]
public int Id { get; set; }
public virtual RecordStatus Status { get; set; }
[NotMapped]
public DateTime? LastModifiedDateTimeUtc { get; set; }
[NotMapped]
public int? LastModifiedBy { get; set; }
[NotMapped]
public string? LastModifiedByName { get; set; }
}
简化使用:
private EfCoreTrackingTestContext _context;
public async Task GenerateMarginRecordsAsync(DateTime asOfDate)
{
// i instantiate here instead of inject just for troubleshooting
await using (_context = InstantiateContext())
{
var businessDate = await _context
.BusinessDates
//.AsNoTracking() // this resulted in nothing being saved
.Include(bd => bd.OtcVariationMarginRecords)
.SingleOrDefaultAsync(bd => bd.Date == asOfDate)
.ConfigureAwait(false);
// nothing here touches the db nor entities that already exist
var newMarginRecords = CalculationLogic();
targetBusinessDate.OtcVariationMarginRecords.AddRange(newMarginRecords);
// error thrown here
await _context.SaveChangesAsync().ConfigureAwait(false);
}
}
private static EfCoreTrackingTestContext InstantiateContext()
{
var optionsBuilder = new DbContextOptionsBuilder<EfCoreTrackingTestContext>();
var options = optionsBuilder
.UseJet(TestDbConfig.ConnectionString.IntegrationTestMarginDb)
.Options;
return new EfCoreTrackingTestContext(options);
}
在 OtcVariationMarginRecord 表中,EF 会自动添加与 FK Business Date(父表)相关的字段,因为它是子表。你可以自己验证一下(我试过)。最好修改一下类,添加FK,这样我们就可以在后面的代码中引用它:
public class OtcVariationMarginRecord : BaseEntity
{
public decimal BaseCurrencyExposure { get; set; }
public decimal BaseCurrency { get; set; }
public decimal TransferAmount { get; set; }
public string CallNature { get; set; }
public bool Direction { get; set; }
public decimal RoundedTransferAmount { get; set; }
public int BusinessDateId { get; set; }
public BusinessDate BusinessDate { get; set; }
}
最后,你可以试试这个代码:
public async Task GenerateMarginRecordsAsync(DateTime asOfDate)
{
await using (_context = InstantiateContext())
{
var targetbusinessDate = await _context
.BusinessDates
.SingleOrDefaultAsync(bd => bd.Date == asOfDate)
.ConfigureAwait(false);
int myId = targetbusinessDate.Id;
_context.Entry(targetbusinessDate).State = EntityState.Unchanged;
var newMarginRecords = CalculationLogic();
foreach (OtcVariationMarginRecord mr in newMarginRecords)
{
mr.Id = 0;
mr.BusinessDateId = myId;
_context.OtcVariationMarginRecords.Add(mr);
}
await _context.SaveChangesAsync().ConfigureAwait(false);
}
}
我将新的 OtcVariationMarginRecords 直接添加到其表中,而不包括父表中的现有记录。 我希望这会对您有所帮助。