Search code examples
c#entity-framework-core.net-5

'Collection is read-only.' when trying to initialise entities


I simply want to get my entities from the db:

var sendingRules = context.Set<SendingRules>().ToList();

But ever since I added an owned type to SendingRules, I get this irritating message:

System.NotSupportedException: 'Collection is read-only.'

The entity in question looks like this

public sealed class SendingRules : Entity<Guid>
{
    private readonly List<SendingRuleLBACFilter> _lbacFilters = new();

    private SendingRules() { }

    public SendingRules(LBACLevels? lbacLevel = null) : base(Guid.NewGuid())
    {
        LBACLevel = lbacLevel;
    }

    public LBACLevels? LBACLevel { get; private set; }

    public IReadOnlyCollection<SendingRuleLBACFilter> LBACFilters => _lbacFilters.AsReadOnly();

    public void AddLBACFilter(SendingRuleLBACFilter lbacFilter)
    {
        EnsureArg.IsNotNull(lbacFilter, nameof(lbacFilter));

        _lbacFilters.Add(lbacFilter);
    }
}

Where

public sealed class SendingRuleLBACFilter : SendingRuleFilter
{
    public SendingRuleLBACFilter(string template) : base(template)
    {
    }
}

Here is my fluent configuration:

builder
    .OwnsMany(
        (sendingRule) => sendingRule.LBACFilters,
        (builder) =>
        {
            builder.ToTable("SendingRuleLBACFilters");
            builder.WithOwner()
                .HasForeignKey("SendingRulesId");
        });
        

I tried adding .Navigation("_lbacFilters")to the end of that configuration call, but then it moans that the property can't be found (even after setting to to public...)

System.InvalidOperationException: Navigation 'SendingRules._lbacFilters' was not found. Please add the navigation to the entity type before configuring it

Does anyone know what the problem is?

at System.ThrowHelper.ThrowNotSupportedException(ExceptionResource resource)
at System.Collections.ObjectModel.ReadOnlyCollection`1.System.Collections.Generic.ICollection<T>.Add(T value)
at Microsoft.EntityFrameworkCore.Metadata.Internal.ClrICollectionAccessor`3.Add(Object entity, Object value, Boolean forMaterialization)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.AddToCollection(INavigationBase navigationBase, InternalEntityEntry value, Boolean forMaterialization)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalMixedEntityEntry.AddToCollection(INavigationBase navigationBase, InternalEntityEntry value, Boolean forMaterialization)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.AddToCollection(InternalEntityEntry entry, INavigationBase navigation, InternalEntityEntry value, Boolean fromQuery)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.SetReferenceOrAddToCollection(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.TrackedFromQuery(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.TrackedFromQuery(InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.MarkUnchangedFromQuery()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTrackingFromQuery(IEntityType baseEntityType, Object entity, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.QueryContext.StartTracking(IEntityType entityType, Object entity, ValueBuffer valueBuffer)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.<PopulateIncludeCollection>g__ProcessCurrentElementRow|60_0[TIncludingEntity,TIncludedEntity](<>c__DisplayClass60_0`2& )
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.PopulateIncludeCollection[TIncludingEntity,TIncludedEntity](Int32 collectionId, QueryContext queryContext, DbDataReader dbDataReader, SingleQueryResultCoordinator resultCoordinator, Func`3 parentIdentifier, Func`3 outerIdentifier, Func`3 selfIdentifier, IReadOnlyList`1 parentIdentifierValueComparers, IReadOnlyList`1 outerIdentifierValueComparers, IReadOnlyList`1 selfIdentifierValueComparers, Func`5 innerShaper, INavigationBase inverseNavigation, Action`2 fixup, Boolean trackingQuery)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
at Microsoft.EntityFrameworkCore.DbContext.RemoveRange(IEnumerable`1 entities)
at Castle.Proxies.Invocations.DbContext_RemoveRange_1.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()

__

I tried changing my config to this

builder
    .OwnsMany<SendingRuleLBACFilter>(
        "_lbacFilters",
        builder =>
        {
            builder.ToTable("SendingRuleLBACFilters");
            builder.WithOwner()
                .HasForeignKey("SendingRulesId");
        }).Navigation(x => x.LBACFilters);

Now it gives me

Unable to determine the relationship represented by navigation 'SendingRules.LBACFilters' of type 'IReadOnlyCollection'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

What is going on?


Solution

  • I got it working after changing the name of my backing field to

    `_lBACFilters`
    

    but that is so lame. If anyone has a nicer solution, where I don't have to have a stupid name I will accept your answer