Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When do I need to specify DbSet in EF's DbContext?

I'm a little bit confused. Until today I thought that every table (used by EF) must be specified in DbContext class. But it looks like I need ONLY one! really?

Let me explain, Here's my DbContext:

public class MyDbContext : DbContext
{
    public MyDbContext()
        : base("name=MyDbContext")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<MyDbContext>(null);
        base.OnModelCreating(modelBuilder);
    }    

    public DbSet<Table1> Table1 { get; set; }
    public DbSet<Table2> Table2 { get; set; }
    public DbSet<Table3> Table3 { get; set; }
    public DbSet<Table4> Table4 { get; set; }
    public DbSet<Table5> Table5 { get; set; }
}

Here are two sample tables, connected 1:many

[Table("Table1")]
public class Table1
{
    [Key]
    [Column("Table1Id", TypeName = "uniqueidentifier")]
    public int Table1Id { get; set; }

    [Column("Table2Id", TypeName = "int")]
    public int Table2Id { get; set; }

    [ForeignKey("Table2Id")]
    public Table2 Table2 { get; set; }
}

[Table("Table2")]
public class Table2
{
    public Table2()
    {
        this.Table1s = new HashSet<Table1>();
    }

    [Key]
    [Column("Table2Id", TypeName = "int")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Table2Id { get; set; }

    public ICollection<Table1> Table1s { get; set; }
} 

Easy. Now, I want to query all Table2s with corresponding Table1s. I do:

var tables2 = fni.Set<Table2>()
    .Include(i => i.Table1s)
    .Where(t => t.Table2Id == 123456).ToList();

It all works, but I was shocked, when I discovered by accident, that it works even with this DbContext:

public class MyDbContext : DbContext
{
    public MyDbContext()
        : base("name=MyDbContext")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<MyDbContext>(null);
        base.OnModelCreating(modelBuilder);
    }    


    public DbSet<Table1> Table1 { get; set; }
}

or this..

public class MyDbContext : DbContext
{
    public MyDbContext()
        : base("name=MyDbContext")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<MyDbContext>(null);
        base.OnModelCreating(modelBuilder);
    }    


    public DbSet<Table2> Table2 { get; set; }
}

Can you explain to me, why does it work? How?

Thanks!

EDIT. It's not include. I was able to do:

var tables2 = fni.Set<Table2>()
    .Where(t => t.Table2Id == 123456).ToList();

having only this: public DbSet<Table1> Table1 { get; set; } in DbContext. It's not even Table2! They are connected via FK (definitions didn't change). So that would mean, that you must have only one table from one "chain" of tables. Is that correct?

like image 913
Marshall Avatar asked Jan 24 '18 21:01

Marshall


1 Answers

Let's look at documentation:

We have the following models:

public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }

public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }

public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }

And DB Context:

public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }

        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }
    }

But:

You could've omitted the DbSet<Enrollment> and DbSet<Course> statements and it would work the same. The Entity Framework would include them implicitly because the Student entity references the Enrollment entity and the Enrollment entity references the Course entity.

PS. Sorry, I just noticed that question not regarding EF Core. But I think it should be true anyway.

like image 173
Alexan Avatar answered Sep 20 '22 23:09

Alexan