Avoid Exposing Private Collection Properties to Entity Framework. DDD principles

安稳与你 提交于 2019-12-02 04:08:43

The linked post is for EF6, while HasData method indicates EF Core. And in EF Core the things are much simpler and do not need any tricks in that regard.

  • EF Core does not require ICollection<T> for collection navigation property. Any public property returning IEnumerable<T> or derived interface / class is discovered by convention as collection navigation property. Hence you can safely expose your collections as IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T> etc.

  • EF Core does not require property setter because it can be configured to use the backing field directly.

Additionally, there is no need of special "EF Constructor" because EF Core supports constructors with parameters.

With that being said, you don't need a custom collection interface / class. The sample model could be like this:

public class CountryRegion
{
    public CountryRegion(string name) => Name = name;    
    public CountryRegion(string id, string name) : this(name) => Id = id;

    public string Id { get; protected set; }
    public string Name { get; protected set; }

    private readonly List<StateProvince> _stateProvinces = new List<StateProvince>(); // Private collection for DDD usage
    public IReadOnlyCollection<StateProvince> StateProvinces => _stateProvinces.AsReadOnly(); // Public like read only collection public immutable exposure
}

public class StateProvince
{
    public StateProvince(string name) => Name = name;
    public StateProvince(string id, string name) : this(name) => Id = id;

    public string Id { get; protected set; }
    public string Name { get; protected set; }

    public string CountryRegionId { get; protected set; }
    public virtual CountryRegion CountryRegion { get; protected set; }
}

and add either the following (simplest - for all properties of all entities)

modelBuilder.UsePropertyAccessMode(PropertyAccessMode.Field);    

or for all properties of CountryRegion

builder.UsePropertyAccessMode(PropertyAccessMode.Field);

or just for that navigation property

builder.HasMany(e => e.StateProvinces)
    .WithOne(e => e.CountryRegion)
    .HasForeignKey(e => e.CountryRegionId)
    .IsRequired()
    .OnDelete(DeleteBehavior.Restrict)
    .Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field);

And that's all. You'll be able to use all EF Core functionality like Include / ThenInclude, "navigating" inside LINQ to Entities queries etc. (including HasData). The backing filed allows EF Core to add/remove elements when needed, or even replace the whole collection (in case the field is not readonly).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!