I'm creating an ASP.NET Core API app, and relying on EF Core. I have entities defined like this:
public class AppUser : IdentityUser { public string FirstName { get; set; } public string LastName { get; set; } [InverseProperty(nameof(Post.Author))] public ICollection<Post> Posts { get; set; } = new List<Post>(); } public class Post { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public string AuthorId { get; set; } [ForeignKey("AuthorId")] public virtual AppUser Author { get; set; } [InverseProperty(nameof(Like.Post))] public ICollection<Like> Likes { get; set; } = new List<Like>(); [InverseProperty(nameof(Comment.Post))] public ICollection<Comment> Comments { get; set; } = new List<Comment>(); }
Where Comment
and Like
are some other entities. Please note that I have simplified the entities for brevity. Then, I want to get the Posts
of a user, but also include the Likes
and Comments
that a post has gotten. So, I did something like this:
return _context.Users .Include(u => u.Location) .Include(u => u.Posts) .ThenInclude(p => p.Comments) .ThenInclude(c => c.Owner) .Include(u => u.Posts) .ThenInclude(p => p.Likes) .ThenInclude(l => l.Giver) .Where(u => u.Id == userId) .FirstOrDefault();
Now, this works fine, but as you can see I'm calling .Include(u = u.Posts)
twice. Is there a way to call ThenInclude
twice on same property, without actually writing the Include
statement also twice?
The easiest way to configure a one-to-many relationship is by convention. EF Core will create a relationship if an entity contains a navigation property. Therefore, the minimum required for a relationship is the presence of a navigation property in the principal entity: public class Author.
For use this, you're going to want to set a breakpoint below your EF Core query. Breakpoint hit after the query. Once the breakpoint is hit hover over query to expand then click on > Debug View > The dropdown beside the magnifying glass> Text Visualizer. There you have it, the SQL that will be sent to the database.
Using Caching in Entity Framework Core. NCache provides integration for caching in Entity Framework Core through Extension Methods. You can cache the result sets of LINQ queries whether they are for transactional data or reference data.
Now, this works fine, but as you can see I'm calling .Include(u = u.Posts) twice. Is there a way to call ThenInclude twice on same property, without actually writing the Include statement also twice?
Calling Include(u => u.Posts)
twice is the right way to do it.
From EF Core docs... emphasis on the last sentence.
You may want to include multiple related entities for one of the entities that is being included. For example, when querying
Blog
s, you includePosts
and then want to include both theAuthor
andTags
of thePosts
. To do this, you need to specify each include path starting at the root. For example,Blog -> Posts -> Author
andBlog -> Posts -> Tags
. This does not mean you will get redundant joins, in most cases EF will consolidate the joins when generating SQL.
using (var context = new BloggingContext()) { var blogs = context.Blogs .Include(blog => blog.Posts) .ThenInclude(post => post.Author) .Include(blog => blog.Posts) .ThenInclude(post => post.Tags) .ToList(); }
You cannot use ThenInclude
with multiple navigation properties. You have to have Include
.
Here is bug opened for this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With