Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support fixed-size collections #24497

Open
Tracked by #240
uladz-zubrycki opened this issue Mar 24, 2021 · 15 comments
Open
Tracked by #240

Support fixed-size collections #24497

uladz-zubrycki opened this issue Mar 24, 2021 · 15 comments

Comments

@uladz-zubrycki
Copy link

Description

Error message is not that descriptive as it could be for a case when fixed size collection (Array) is used for a navigation property.
It'd be nice to be pointed to the problematic navigation property or entity type at least with a clean problem description in the error message.

Creating issue because of the conversation happening here #6589 (comment)

Could the exception message be more intuitive, please? It took me a while to find the cause of this problem, whereas if it had said something different I might have got it quicker
"Association property instances cannot be a fixed length type, such as an Array"
Note how I said "instances" so as not to mislead people into thinking they cannot declare the property type as IEnumerable

This issue is very old. If you're still seeing this exception with EF Core 3.1 or 5.0, then please open a new issue and
attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

Code

I reproduced the issue on a sample used for another issue in this repo previously, so it's not that minimal (and won't probably work even, when this fixed collection case is improved, due to another configuration error), but should be okay for the error discussed.
Repro.zip

Include provider and version information

EF Core version: 3.1.12
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: net48
Operating system: Windows 10
IDE: Visual Studio 2019 16.3

@ajcvickers
Copy link
Member

Note for triage:

Unhandled exception. System.NotSupportedException: Collection was of a fixed size.
   at System.SZArrayHelper.Remove[T](T value)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.ClrICollectionAccessor`3.Remove(Object entity, Object value)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.RemoveFromCollection(INavigation navigation, InternalEntityEntry value)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.RemoveFromCollection(InternalEntityEntry entry, INavigation navigation, InternalEntityEntry value)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.KeyPropertyChanged(InternalEntityEntry entry, IProperty property, IReadOnlyList`1 containingPrincipalKeys, IReadOnlyList`1 containingForeignKeys, Object oldValue, Object newValue)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.KeyPropertyChanged(InternalEntityEntry entry, IProperty property, IReadOnlyList`1 keys, IReadOnlyList`1 foreignKeys, Object oldValue, Object newValue)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectKeyChange(InternalEntityEntry entry, IProperty property)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.PropertyChanged(InternalEntityEntry entry, IPropertyBase propertyBase, Boolean setModified)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.PropertyChanged(InternalEntityEntry entry, IPropertyBase property, Boolean setModified)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetProperty(IPropertyBase propertyBase, Object value, Boolean isMaterialization, Boolean setModified, Boolean isCascadeDelete, CurrentValueType valueType)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetTemporaryValue(IProperty property, Object value, Boolean setModified)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.SetForeignKeyProperties(InternalEntityEntry dependentEntry, InternalEntityEntry principalEntry, IForeignKey foreignKey, Boolean setModified, Boolean fromQuery)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.FixupToPrincipal(InternalEntityEntry dependentEntry, InternalEntityEntry principalEntry, IForeignKey foreignKey, Boolean setModified, Boolean fromQuery)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.DelayedFixup(InternalEntityEntry entry, INavigation navigation, InternalEntityEntry referencedEntry, Boolean fromQuery)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.InitialFixup(InternalEntityEntry entry, Boolean fromQuery)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.StateChanged(InternalEntityEntry entry, EntityState oldState, Boolean fromQuery)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.StateChanged(InternalEntityEntry entry, EntityState oldState, Boolean fromQuery)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.FireStateChanged(EntityState oldState)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode`1 node)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState(InternalEntityEntry entry, EntityState entityState)
   at Microsoft.EntityFrameworkCore.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)
   at Microsoft.EntityFrameworkCore.DbContext.Add[TEntity](TEntity entity)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.Add(TEntity entity)
   at Repro.Program.Main(String[] args) in C:\Stuff\AllTogetherNow\ThreeOne\ThreeOneApp.cs:line 23

@ajcvickers
Copy link
Member

Putting this on the backlog to check the first time we create a property accessor. This won't help in all cases because the property can be assigned a new instance of a different type at any time, and we don't want to do an additional check every time we access the property.

@FrankIceBass
Copy link

Hi, I have exactly the same problem on the latest version.

Include provider and version information

EF Core version: 5.0.10
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .Net Core 5.0
Operating system: Windows 10
IDE: Visual Studio 2019 16.11.3

Here is the log:
System.NotSupportedException: Collection was of a fixed size. at System.SZArrayHelper.Add[T](T value) at Microsoft.EntityFrameworkCore.Metadata.Internal.ClrICollectionAccessor`3.Add(Object entity, Object value, Boolean forMaterialization) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.AddToCollection(InternalEntityEntry entry, INavigationBase navigation, InternalEntityEntry value, Boolean fromQuery) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.ToDependentFixup(InternalEntityEntry dependentEntry, InternalEntityEntry principalEntry, IForeignKey foreignKey, Boolean fromQuery) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.InitialFixup(InternalEntityEntry entry, Boolean fromQuery) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.StateChanged(InternalEntityEntry entry, EntityState oldState, Boolean fromQuery) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.StateChanged(InternalEntityEntry entry, EntityState oldState, Boolean fromQuery) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.FireStateChanged(EntityState oldState) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityStateAsync(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintActionAsync(EntityEntryGraphNode`1 node, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraphAsync[TState](EntityEntryGraphNode`1 node, Func`3 handleNode, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.AddRangeAsync(IEnumerable`1 entities, CancellationToken cancellationToken) at WatchMyGame.Web.Dal.Services.ImportDataService.UpdateProjectsAsync(User user, String projectData, Boolean isManager, IDictionary`2 projects, CancellationToken cancellationToken) in C:\Lavoro\Git\WatchMyGame\Src\WatchMyGame.Web.Dal\Services\ImportDataService.cs:line 238 at WatchMyGame.Web.Dal.Services.ImportDataService.UpdateUserAsync(Int64 seasonId, User user, UserSeason userSeason, ImportAnagraficaItemModel anagrafica, IDictionary`2 projects, UserImportConfirmRequest config, CancellationToken cancellationToken) in C:\Lavoro\Git\WatchMyGame\Src\WatchMyGame.Web.Dal\Services\ImportDataService.cs:line 306 at WatchMyGame.Web.Dal.Services.ImportDataService.ProcessUserAsync(Int64 seasonId, User user, UserSeason userSeason, ImportAnagraficaItemModel anagrafica, IDictionary`2 projects, UserImportConfirmRequest config, CancellationToken cancellationToken) in C:\Lavoro\Git\WatchMyGame\Src\WatchMyGame.Web.Dal\Services\ImportDataService.cs:line 352 at WatchMyGame.Web.Dal.Services.ImportDataService.ConfirmImportAnagraficaAsync(Int64 userId, Int64 seasonId, UserImportConfirmRequest config, CancellationToken cancellationToken) in C:\Lavoro\Git\WatchMyGame\Src\WatchMyGame.Web.Dal\Services\ImportDataService.cs:line 94 at WatchMyGame.Web.Services.ImportService.ConfirmImportAnagraficaAsync(Int64 userId, Int64 seasonId, UserImportConfirmRequest request, CancellationToken cancellationToken) in C:\Lavoro\Git\WatchMyGame\Src\WatchMyGame.Web.Services\Services\ImportService.cs:line 117 at WatchMyGame.Web.Controllers.Api.ImportController.ConfirmAnagraficaAsync(UserImportConfirmRequest request, CancellationToken cancellationToken) in C:\Lavoro\Git\WatchMyGame\Src\WatchMyGame.Web\Controllers\Api\ImportController.cs:line 86 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

@ajcvickers
Copy link
Member

@FrankIceBass Fixed-size collections, such as arrays, are not supported since EF needs to add elements to them.

@FrankIceBass
Copy link

@ajcvickers I hardly understand which is the fixed-size collections. I'm adding items to a DbSet with AddRangeAsync.
I'm using just this on DbSet:

await this.context.ProjectUsers.AddRangeAsync(list, cancellationToken);

@ajcvickers
Copy link
Member

@FrankIceBass Typically a collection of one entity type on another entity type. For example, the collection of posts on a blog. This is known as a navigation. See Relationships in the docs.

@FrankIceBass
Copy link

@ajcvickers I really hardly understand. I'm using scaffolded db context and it is just a 1-N table. I will try to check more why this "feature" is annoying me so much.
By the way I have the same exception even if i try to update objects into that DbSet.

Anyway.. thank you for your support.

@ajcvickers
Copy link
Member

@FrankIceBass Feel free to open a new issue attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

@uladz-zubrycki
Copy link
Author

@FrankIceBass I'd guess that you are using sth like Array to initialize the navigation property from 1 to N for your relation somewhere during the entity instance initialization.

See the repro I attached initially, it might shed some light.

@FrankIceBass
Copy link

@v-zubritsky unfortunately it's not my case.

I have the same exception even trying to add items not related to parent entities.

var list = projectList.Where(item => !userProjects.Where(y => y.ProjectId == item.Id).Any())
.Select(x => new Ef.ProjectUser
{
CreationDate = DateTime.UtcNow,
Deleted = false,
IsManager = isManager,
LastUpdate = DateTime.UtcNow,
ProjectId = x.Id,
UserId = user.Id
}).ToList();

            await this.context.ProjectUsers.AddRangeAsync(list, cancellationToken);

@FrankIceBass
Copy link

FrankIceBass commented Sep 18, 2021

Hi everyone, I just solved it... well... it's strange solution but it worked for me. I was watching this.context.ChangeTracker.Entries() and it was full of unchanged properties.
I just added this.context.ChangeTracker.Clear() before running the code I posted above... well... it worked...

@AndriySvyryd AndriySvyryd changed the title Fails with "Collection was of a fixed size" Support fixed-size collections Jan 13, 2022
@omuleanu
Copy link

omuleanu commented Aug 4, 2022

Calling .ToList() solved the problem for me.
I was getting the above error message ( Collection was of a fixed size. at System.SZArrayHelper.Remove...) ,
when I was setting
model.Foos = newFoos;
only when model.Foos count was 1 and newFoos was more than 1 or the other way around.

@rombethor
Copy link

I feel the need to weigh in here, having encountered this error and scratched my head for over an hour as to where the fixed array was, why it updated and why it was failing to 'Remove' with an 'Add'.

Firstly, the exception misled me because I was performing a .Add(entity1) followed by a .Remove(entity2). The exception was being thrown on the add.

Secondly, the fixed array was not in either entity1 or entity2. My schema looked like the following:

[Table]
public class A
{
  [Key]
  public int AId { get; set; }
  public IList<B>? Bs { get; set; } = new List<B>();
}

[Table]
public class B
{
  public int AId { get; set; }
  public int CId { get; set; }
  [ForeignKey("AId")]
  public IList<A> A { get; set; }
  [ForeignKey("CId")]
  public IList<C> C { get; set; }
}


[Table]
public class C
{
  [Key]
  public int CId { get; set; }
  
  //I'd set as an array to avoid updating from here.
  public IEnumerable<B> Bs { get; set; } = Array.Empty<B>();
}

Then when trying to add an A, with a bunch of Bs in the list, I believe in the background it wanted to update the Array of Cs through the change tracking.

In brief:

MyDbContext db = new(options);

//Perhaps I loaded some Cs earlier on in the same DbContext, bringing them into the local change tracking, perhaps why clearing the change tracking has worked for others
var bunchOfCs = db.Cs.ToList();

A myA = new();
myA.Bs.Add(new B() { AId = 123, BId = 234 });

db.As.Add(myA); //throws error

Changing the C.Bs to a List allowed it to run.

In conclusion, it might be a good idea to add a warning of this type of background behaviour along with the exception.

@FreddyJohn
Copy link

@FrankIceBass Fixed-size collections, such as arrays, are not supported since EF needs to add elements to them.

How is it not possible to take a fixed sized array and convert it into an array that is growable and not fixed?

@cincuranet
Copy link
Contributor

How is it not possible to take a fixed sized array and convert it into an array that is growable and not fixed?

Arrays in C#/.NET are always fixed size. List<T>, for example, can grow as required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants