w0051977
w0051977

Reputation: 15787

EF Core and an encapsulated collection

I am trying to follow the advice here: https://ardalis.com/encapsulated-collections-in-entity-framework-core

I have a class, which looks like this:

public class Person
{
    public Guid Id { get; private set; }
    public string Name { get; private set; }
    private readonly List<PersonSport> _entries = new List<PersonSport>();
    public IEnumerable<PersonSport> Entries => _entries.AsReadOnly();

    public void AddEntry(PersonSport entry)
    {
        _entries.Add(entry);
    }
}

and a dbcontext, which looks like this:

public class PersonSportContext : DbContext
{
    public DbSet<Person> Person { get; set; }
    public DbSet<Sport> Sport{ get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<PersonSport>().HasKey(sc => new { sc.PersonId, sc.SportId });
        modelBuilder.Entity<Sport>()
       .ToTable("Sport")
       .HasDiscriminator<string>("SportType")
       .HasValue<Football>("Football")
       .HasValue<Running>("Running");

        modelBuilder.Entity<PersonSport>()
            .HasOne<Person>(sc => sc.Person)
            .WithMany(s => s.PersonSport)
            .HasForeignKey(sc => sc.PersonId);


        modelBuilder.Entity<PersonSport>()
            .HasOne<Sport>(sc => sc.Sport)
            .WithMany(s => s.PersonSport)
            .HasForeignKey(sc => sc.SportId);

        var navigation = modelBuilder.Entity<Person>().Metadata.FindNavigation(nameof(ConsoleApp1.Person.PersonSport));
        navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=PersonSport;Trusted_Connection=True;MultipleActiveResultSets=true");
    }

I see a compilation error:

"DbSet does not contain a definition for Entries".

I have highlighted the line that errors using a comment ('Entries' is underlined in red due to the compilation error). I have spent hours Googling this and have got nowhere. What am I doing wrong please?

Update cwharris's answer has helped with the compilation error. It now runs. I have created a Console app to test it:

static void Main(string[] args)
        {
            PersonSportContext personSportContext = new PersonSportContext();
            var person = personSportContext.Person.Include(t => t.PersonSport).FirstOrDefault(); 
            var sport = personSportContext.Sport.Include(t => t.PersonSport).FirstOrDefault();
            Console.WriteLine("Finished");
        }

Please see the screenshot below:

enter image description here

Notice that Person.PersonSport.Sport is null. Now see the below (when I stop the debugger on the following line):

enter image description here

Notice that Person.PersonSport.Sport is not null anymore.

Why is this? How can I ensure that Person.PersonSport.Sport is opulated when I populate the Person variable?

Upvotes: 1

Views: 610

Answers (1)

cwharris
cwharris

Reputation: 18125

It looks like nameof(Person.Entries) is intended to reference the Person class, but is in fact looking at the Person property of the PersonSportContext class, due to a lack of name-spacing. Try prepending the Person class namespace within the nameof operator.

nameof(Person.Entries)

should become

nameof(MyNamespaceWherePersonClassResides.Person.Entries)

Upvotes: 4

Related Questions