Globally Exclude/Optional component fails with EF Core error on SQLite storage provider
- Dominant language
- C#
- Stars
- 604
- Forks
- 1.3k
- Avg merge
- 5d 14h
- Merged PRs (30d)
- 3
Description
**Tool version**
Current version of the Azure Naming Tool you are running: **5.0.2**
**Describe the bug**
When editing a component and using `"Globally Exclude Configuration" → ADD` to **exclude** the component **for all resource types,** the operation fails with an `[InvalidOperationException]` from `[SQLiteConfigurationRepository.SaveAllAsync()]`.
The toast initially shows the component was `"ADDED as EXCLUDE!"` but the underlying save operation throws an EF Core `[SaveChangesAsync]` error. The same issue affects `"Globally Optional Configuration" → ADD`.
This bug only affects the **SQLite storage provider**. JSON file storage is unaffected because file writes are stateless.
**To Reproduce**
1. Use SQLite storage provider (default for v5.0.0+).
2. Go to Configuration → any component section (e.g. Custom Components).
3. Click Edit on a component.
4. Expand "Globally Exclude Configuration".
5. Click `ADD` ("This option will ADD the component as EXCLUDE for all resource types").
6. Click `UPDATE`.
7. Observe EF Core `[InvalidOperationException]` error (see screenshots).
**Expected behaviour**
The component should be successfully added to the Exclude list for all resource types without error.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Installation Method**
Azure App Service (Linux), SQLite storage provider, deployed via GitHub Actions CI/CD.
**Additional context**
Root cause:
`[ResourceTypeService.UpdateTypeComponentsAsync()]` (line 441) iterates over all resource types and calls `[PostItemAsync()]` for each one individually:
```
foreach (ResourceType currenttype in resourceTypes)
{
// ...modify currenttype.Exclude...
await PostItemAsync(currenttype); // ← called per resource type
}
```
`[PostItemAsync()]` calls `[_repository.SaveAllAsync()]` which:
1. Removes ALL entities from the DbSet `([_dbSet.RemoveRange(existingEntities)]`
2. Re-adds ALL entities `([_dbSet.AddRangeAsync(entities)]`
3. Calls `[SaveChangesAsync()]`
On the second iteration, the EF Core change tracker still holds entities from the first [SaveAllAsync()] call. When it tries to add entities with the same primary keys, EF Core throws an [InvalidOperationException].
This pattern works with JSON file storage (stateless writes) but breaks with SQLite/EF Core due to entity tracking state.
**Suggested fix:**
Batch the changes and save once after the loop:
```
foreach (ResourceType currenttype in resourceTypes)
{
switch (operation)
{
case "exclude-add":
var currentvalues = new List(currenttype.Exclude.Split(','));
if (!currentvalues.Contains(component))
{
currentvalues.Add(component);
currenttype.Exclude = String.Join(",", currentvalues);
}
break;
// ...other cases...
}
}
// Save all resource types once after modifications
await _repository.SaveAllAsync(resourceTypes.OrderBy(x => x.Id).ToList());
```
Alternatively, clear/detach the DbContext change tracker between iterations, or use a dedicated `UpdateAsync` method that doesn't delete-and-reinsert the entire collection.
Contributor guide
Research direction
Start in ResourceTypeService.UpdateTypeComponentsAsync and follow its calls to PostItemAsync and SQLiteConfigurationRepository.SaveAllAsync. Reproduce the exclude and optional operations with SQLite, then verify that changes are saved without an EF Core tracking error and that both configurations apply to all resource types.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, sqlite
- Domain
- backend, database
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100