I am going to add a record in my database, but before that, I update other records. The reason is that I have a sequence field in the records like something: Name Sequence Spring 1 Autumn 2
I want to put summer in between thus need to first update the sequence field of Autumn to 3. (the actual code is not about summer and autumn though).
The code that is doing this is as follows:
List<IdAndSequence> ExistingLevels = (from c in _classificationLevel.GetAllClassificationLevels()
where c.Id == NewLevel.SuObject.ObjectId
&& c.Sequence >= NewLevel.SuObject.Sequence
select new IdAndSequence
{
Id = c.Id
, Sequence = c.Sequence
}).ToList();
int x = 0;
while (x < ExistingLevels.Count())
{
SuClassificationLevelModel u = new SuClassificationLevelModel();
u.Sequence = ExistingLevels[x].Sequence++;
u.Id = ExistingLevels[x].Id;
_classificationLevel.UpdateClassificationLevel(u);
x++;
}
The get all classificationlevels is coming from:
public IEnumerable<SuClassificationLevelModel> GetAllClassificationLevels()
{
return context.dbClassificationLevel.AsNoTracking();
}
And the UpdateClassificationLevel is coming from:
public SuClassificationLevelModel UpdateClassificationLevel(SuClassificationLevelModel suClassificationLevelChanges)
{
var suClassificationLevel = context.dbClassificationLevel.Attach(suClassificationLevelChanges);
suClassificationLevel.State = Microsoft.EntityFrameworkCore.EntityState.Modified;
context.SaveChanges();
return suClassificationLevelChanges;
}
When the program is at:
_classificationLevel.UpdateClassificationLevel(u);
I get the error:
InvalidOperationException: The instance of entity type 'SuClassificationLevelModel' 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.
I have tried to use at several places AsNoTracking() but that didn't work either.
Any suggestions? Or is the cause in other areas of my code?
UPDATE
The code before this is first of all to check if there are any records already in the system. (it also checks the language used by the user but that is on a different model.)
[HttpPost]
public async Task<IActionResult> LevelCreate(SuObjectAndStatusViewModel NewLevel)
{
if (ModelState.IsValid)
{
var CurrentUser = await userManager.GetUserAsync(User);
var DefaultLanguageID = CurrentUser.DefaultLangauge;
var TestForNull = (from c in _classificationLevelVMRepository.GetAllClassificationLevels()
join l in _classificationLevelVMRepository.GetAllClassificationLevelLanguages()
on c.Id equals l.ClassificationLevelId
where c.ClassificationId == NewLevel.SuObject.ObjectId
&& l.LanguageId == DefaultLanguageID
select c.Sequence).Count();
If there are no records then the sequence will be 1:
int MaxLevelSequence;
if (TestForNull == 0)
{ MaxLevelSequence = 1; }
If there are already records then it will check what the highest sequence is:
{
MaxLevelSequence = (from c in
_classificationLevelVMRepository.GetAllClassificationLevels()
join l in
_classificationLevelVMRepository.GetAllClassificationLevelLanguages()
on c.Id equals l.ClassificationLevelId
where c.ClassificationId == NewLevel.SuObject.ObjectId
&& l.LanguageId == DefaultLanguageID
select c.Sequence).Max();
MaxLevelSequence++;
}
Then it will check if the new record was going to be at the end or in the middle of the sequence of the existing records. This because if it is at the end, then the existing records don't need to be updated:
if (NewLevel.SuObject.Sequence != MaxLevelSequence)
{
After that it is as the code in the beginning of the explanation.
The following is called (through a interface):
public IEnumerable<SuClassificationLevelModel>
GetAllClassificationLevels()
{
return context.dbClassificationLevel.AsNoTracking();
}
UPDATE When I add the AsNoTracking() to:
public IEnumerable<SuClassificationLevelModel> GetAllClassificationLevels()
{
return context.dbClassificationLevel.AsNoTracking();
}
I get an error on the following code:
var TestForNull = (from c in
_classificationLevel.GetAllClassificationLevels() join l in _classificationLevelLanguage.GetAllClassificationLevelLanguages() on c.Id equals l.ClassificationLevelId where c.ClassificationId == NewLevel.SuObject.ObjectId && l.LanguageId == DefaultLanguageID select c.Sequence).Count();
The error is:
InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext, however instance members are not guaranteed to be thread safe. This could also be caused by a nested query being evaluated on the client, if this is the case rewrite the query avoiding nested invocations.