Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to setup readonly collection property with backing field in EF Core 2.2

I am trying to create an entity class which will expose a related collection through a readonly property, like this:

public class MyEntity: Entity
{
    public int Id{ get; private set; }
    private IList<RelatedEntity> _relatedEntities = new List<RelatedEntity>();
    public IReadOnlyList<RelatedEntity> RelatedEntities => _relatedEntities.ToList().AsReadOnly();
}

The builder class looks like this:

public void Configure(EntityTypeBuilder<MyEntity> builder)
{
    builder.HasKey(x=>x.Id);
    builder.Property<IReadOnlyList<RelatedEntity>>("RelatedEntities")
        .HasField("_relatedEntities ")
        .UsePropertyAccessMode(PropertyAccessMode.Field);
}

It builds but crashes at runtime with the exception:

InvalidOperationException: The specified field '_relatedEntities' of type 'IList' cannot be used for the property 'MyEntity.RelatedEntities ' of type 'IReadOnlyList'. Only backing fields of types that are assignable from the property type can be used.

Could you provide a working example how to deal with this issue ?

like image 401
vanpersil Avatar asked Sep 21 '19 17:09

vanpersil


3 Answers

I ckeck this and it worked:

private readonly List<RelatedEntity> _relatedEntitys;
public IReadOnlyCollection<RelatedEntity> RelatedEntitys => _relatedEntitys;

And configuration must be like below:

    builder.HasMany(x => x.RelatedEntitys)
        .WithOne()
        .IsRequired()
        .HasForeignKey(x => x.RelatedEntityId)
        .OnDelete(DeleteBehavior.Cascade);

    builder.Metadata
        .FindNavigation("RelatedEntitys")
        .SetPropertyAccessMode(PropertyAccessMode.Field);
like image 53
Mohammad Niazmand Avatar answered Oct 22 '22 16:10

Mohammad Niazmand


EF core requires you to use concrete types for backing fields. You need to change your code to:

private readonly List<RelatedEntity> _relatedEntities = new List<RelatedEntity>();
public IReadOnlyList<RelatedEntity> RelatedEntities => _relatedEntities.ToList();
like image 22
Piotr K. Avatar answered Oct 22 '22 18:10

Piotr K.


The error message is loud and clear:

IList is not assignable to IReadOnlyList

Changing the property type to the same type as the backing field will do the trick.

Update:

Because IEnumerable<T> is read-only by default, this would be your best bet I believe.

    public class MyEntity: Entity
    {
        public int Id { get; private set; }

        private readonly List<RelatedEntity> _relatedEntities = _collection.ToList().AsReadOnly();

        public IEnumerable<RelatedEntity> RelatedEntities => _relatedEntities;
    }

Update your fluent API as follows:

    builder.HasKey(x=>x.Id);
    builder.Metadata.FindNavigation("RelatedEntities")
        .UsePropertyAccessMode(PropertyAccessMode.Field);
like image 1
Dennis VW Avatar answered Oct 22 '22 18:10

Dennis VW