question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Query: Optimize navigation property translation in projections

See original GitHub issue

For example, customers.Select(c => new { c.Id, Orders = c.Orders }) results in n+1 at the moment.

Make sure to consider the following scenarios when looking at this:

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Reactions:2
  • Comments:16 (10 by maintainers)

github_iconTop GitHub Comments

16reactions
maumarcommented, Nov 21, 2017

@MaklaCof I’m working on this feature right now. Its scheduled to be shipped with the next release of EF Core. Unless I encounter some unexpected issues the code should be in our dev branch in a next couple weeks or so - ready to be tested

3reactions
maumarcommented, Jun 27, 2017

@simeyla here is a sample of how a manually created query (using joins) would look like:

        public class MyContext : DbContext
        {
            public DbSet<Email> Emails { get; set; }

            public DbSet<Tag> Tags { get; set; }

            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                optionsBuilder.UseSqlServer(@"Server=.;Database=Sample4007;Trusted_Connection=True;MultipleActiveResultSets=True");
            }
        }

        public class EmailDto
        {
            public string Subject { get; set; }

            public List<TagDto> Tags { get; set; }
        }

        public class TagDto
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }

        public class Email
        {
            public int Id { get; set; }
            public string Subject { get; set; }

            public List<Tag> Tags { get; set; }
        }

        public class Tag
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int EmailId { get; set; }

            public Email Email { get; set; }
        }

        public void ManualQuerySample()
        {
            using (var ctx = new MyContext())
            {
                ctx.Database.EnsureDeleted();
                ctx.Database.EnsureCreated();

                var t11 = new Tag { Name = "t11" };
                var t12 = new Tag { Name = "t12" };
                var t13 = new Tag { Name = "t13" };
                var t21 = new Tag { Name = "t21" };
                var t22 = new Tag { Name = "t22" };
                var t31 = new Tag { Name = "t31" };

                var e1 = new Email { Subject = "email1", Tags = new List<Tag> { t11, t12, t13 } };
                var e2 = new Email { Subject = "email2", Tags = new List<Tag> { t21, t22 } };
                var e3 = new Email { Subject = "email3", Tags = new List<Tag> { t31 } };

                ctx.Tags.AddRange(t11, t12, t13, t21, t22, t31);
                ctx.Emails.AddRange(e1, e2, e3);
                ctx.SaveChanges();

                var emails = ctx.Emails.ToList();
            }

            using (var ctx = new MyContext())
            {
                var query = from e in ctx.Emails
                            where e.Id < 3
                            join t in ctx.Tags on e.Id equals t.EmailId into grouping
                            from t in grouping.Where(g => !g.Name.EndsWith("1")).DefaultIfEmpty()
                            select new { Email = e, t.Name };

                var result = query.ToList()
                        .GroupBy(key => key.Email, element => element.Name)
                        .Select(g => new EmailDto { Subject = g.Key.Subject, Tags = g.Select(t => new TagDto { Name = t }).ToList() });
            }
        }

It’s quite tricky to write, but you can do filtering and custom projections on inner and outer collections. Basically the idea is to create a groupjoin, which pairs up the email entities and their tags - you can apply filter on emails directly (see: where e.Id >3, and filters to tags are applied on the grouping, see from t in grouping.Where(g => !g.Name.EndsWith("1")).DefaultIfEmpty()

When you apply all the filters, you project both into anonymous type. This will produce the following SQL, that fetches all the (filtered) emails and tags in one query:

SELECT [e].[Id], [e].[Subject], [t0].[Name]
FROM [Emails] AS [e]
LEFT JOIN (
    SELECT [t].*
    FROM [Tags] AS [t]
    WHERE RIGHT([t].[Name], LEN(N'1')) <> N'1'
) AS [t0] ON [e].[Id] = [t0].[EmailId]
WHERE [e].[Id] < 3

now you need to group by the results by email, and shape the result into DTOs

Read more comments on GitHub >

github_iconTop Results From Across the Web

Query: Optimize navigation property translation in ...
The workaround would be to retrieve the scalar properties in one query and then pull back the children in a separate query. If...
Read more >
How to: Use Projections to Create Custom Queries and ...
How to: Use Projections to Create Custom Queries and Optimize Performance ... Step 3 - Include Navigation Properties to the Items Loaded to...
Read more >
Optimising Entity Framework Core Queries using Projection
Summary. We've seen that we can optimise the queries generated by Entity Framework by using a technique called projection, which allows Entity ...
Read more >
Efficient Querying - EF Core
Project only properties you need. EF Core makes it very easy to query out entity instances, and then use those instances in code....
Read more >
EF core 2.1 using take in projection
We have improved our query translation to avoid executing "N + 1" SQL queries in many common scenarios in which the usage of...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found