5

I've started to use .NET Core 2 and databases for the first time and looked at examples like: Getting Started with EF Core on .NET Core Console App with a New database. I've got a few models, like

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

But if I load an object, like Post post = context.Post.SingleOrDefault(s => s.PostId == id) then post.Blog is null. But if I before reading from the database, expand context.Blogs in the debugger, then post.Blog is a valid object after reading from the database with the above command.

So it feels like I need to read the blogs from the database to load those so the reference from Post will be correct. What is the correct way of doing this?

Second question: how to get the database context from anywhere? Should I have a default constructor with a connection string set in the constructor and create a new context all the time?

Mackan
  • 1,305
  • 2
  • 17
  • 30
  • Built in dependency injection for your second question: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection – Harutyun Imirzyan Feb 13 '18 at 10:48
  • Eager and Explicit loading for your first question: https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/read-related-data EF core 2.0 doesn't support lazy loading – Harutyun Imirzyan Feb 13 '18 at 10:50

3 Answers3

8

Take a look here for detailed explanation: https://learn.microsoft.com/en-us/ef/core/querying/related-data

A few examples from the link above:

Eager loading

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ToList();
}

Explicit loading

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Single(b => b.BlogId == 1);

    context.Entry(blog)
        .Collection(b => b.Posts)
        .Load();
}

Lazy loading is not yet supported. It should be coming in v2.1.

Daniel P
  • 3,314
  • 1
  • 36
  • 38
  • 1
    Thanks! I will look in to that! Btw, if I have a database singleton class, should I in each call create a new context? And use a default constructor without parameters.. – Mackan Feb 13 '18 at 11:11
  • @Mackan yes - create new context every time, never use signleton context, or you will have a lot of troubles. – Evk Feb 13 '18 at 11:34
  • @Evk If I have a default constructor, I get this error https://stackoverflow.com/questions/40745468/no-database-provider-has-been-configured-for-this-dbcontext And if I remove the parameterless constructor, then I can't create a context like that. – Mackan Feb 13 '18 at 12:11
  • @Mackan well to be honest I have no idea about that, because I never create\update databases from EF, I always use "database first". – Evk Feb 13 '18 at 12:22
1

Just to keep this updated for future reference, EF Core now supports lazy loading.

https://learn.microsoft.com/en-us/ef/core/querying/related-data

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
    .UseLazyLoadingProxies()
    .UseSqlServer(myConnectionString);

This should solve the problem.

Fernando Moreira
  • 785
  • 4
  • 16
  • 1
    You must install NuGet package `Microsoft.EntiryFrameworkCore.Proxies` for this to work (which it says in the docs). – Chaim Eliyah Jan 12 '19 at 08:49
0

EF Core does not support lazy loading. You will need to eager load the objects using .Include

The reason it worked when you called the Blogs first, is that the object was available in the context cache and hence it was able to populate the Blog object successfully.

Praveen Paulose
  • 5,741
  • 1
  • 15
  • 19