I'm trying to store older versions of entities in my database. To do that I am copying the existing values before I update them. For some reason EF Core won't let me use the same batch.Values
property twice.
public async Task<Batch> UpdateBatch(Batch batch, Batch updatedBatch)
{
foreach (var valueParameter in batch.Values)
{
batch.ValuesHistory.Add(new ParameterValueHistory
{
Parameter = valueParameter.Parameter,
ParameterBatchNumber = valueParameter.ParameterBatchNumber,
Value = valueParameter.Value
});
}
batch.Values = updatedBatch.Values;
batch.Version++;
await this.context.SaveChangesAsync();
return batch;
}
The foreach
loop and batch.Values = updatedBatch.Values;
work exactly like they should when only one of them exists. But whenever they're both active I get the following error:
The instance of entity type 'ParameterValue' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
These are the relevant models: ParameterValue:
public class ParameterValue
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[Required]
public virtual RecipeParameter Parameter { get; set; }
public string Value { get; set; }
public string? ParameterBatchNumber { get; set; }
}
ParameterValueHistory:
public class ParameterValueHistory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[Required]
public virtual RecipeParameter Parameter { get; set; }
public string Value { get; set; }
public string? ParameterBatchNumber { get; set; }
}
RecipeParameter for context:
public class RecipeParameter
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Type { get; set; }
public string Unit { get; set; }
public string Value { get; set; }
public bool BatchRequired { get; set; }
}
Batch:
public class Batch
{
[Key]
[MaxLength(12)]
public string BatchNumber { get; set; }
public virtual List<ParameterValue> Values { get; set; }
public virtual List<ParameterValueHistory> ValuesHistory { get; set; }
public int Version { get; set; }
[Required]
public bool IsResearch { get; set; }
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime CreatedOn { get; set; } = DateTime.UtcNow;
}
This is my DbContext class:
public class ApplicationDataContext : DbContext
{
public ApplicationDataContext(DbContextOptions<ApplicationDataContext> options)
: base(options)
{
}
public DbSet<Product> Product { get; set; }
public DbSet<Batch> Batch { get; set; }
public DbSet<ParameterValue> ParameterValue { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies();
base.OnConfiguring(optionsBuilder);
}
}
Why does this error keep showing up? Even when I am just accessing the propety as batch.Values
more than once, it gives me this error.
UPDATE:
This is the controller method that calls the UpdateBatch
method.
[HttpPut("{productId}/batches/{batchNumber}")]
public async Task<ActionResult<Batch>> PutBatch(string batchNumber, Batch updatedBatch)
{
Batch batch = await this.repository.GetBatchByBatchNumber(batchNumber);
if (batch == null)
{
return NotFound()
}
return await this.repository.UpdateBatch(batch, updatedBatch);
}
Batch batch, Batch updatedBatch
are the same, show how they were passed to this function, usually u fetch the entity... this would be the one which is tracked, the other is not, in your case for some reason it is... its like you did fetch twice and modified one of them – SeabizkitUpdateBatch
is called... it needs to be tweeked somewhere there... where the instances ofBatch batch, Batch updatedBatch
originate – Seabizkit