Consider the following classes:
public class Foo
{
public int Id { get; set; }
public string Type { get; set; }
public int BarId { get; set; }
}
public class Bar
{
public int Id { get; set; }
public string Name { get; set; }
}
and the following DbContext:
public class TestDbContext : DbContext
{
public DbSet<Foo> Foos { get; set; }
public DbSet<Bar> Bars { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=.;Database=ConditionalJoinEFCoreTest;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Foo>().HasData(new Foo { Id = 1, BarId = 1, Type = "Bar" });
modelBuilder.Entity<Foo>().HasData(new Foo { Id = 2, BarId = 2, Type = "Bar" });
modelBuilder.Entity<Foo>().HasData(new Foo { Id = 3, BarId = 1, Type = "Not Bar" });
modelBuilder.Entity<Foo>().HasData(new Foo { Id = 4, BarId = 2, Type = "Not Bar" });
modelBuilder.Entity<Bar>().HasData(new Bar { Id = 1, Name = "Bar 1" });
modelBuilder.Entity<Bar>().HasData(new Bar { Id = 2, Name = "Bar 2" });
}
}
Now let's query the data:
using (var ctx = new TestDbContext())
{
var joinResult = ctx.Foos.GroupJoin(
ctx.Bars,
foo => new { Key = foo.BarId, PropName = foo.Type },
bar => new { Key = bar.Id, PropName = "Bar" },
(foo, bars) => new
{
Foo = foo,
Bars = bars
})
.SelectMany(
x => x.Bars.DefaultIfEmpty(),
(foo, bar) => new
{
Foo = foo.Foo,
Bar = bar.Name
});
var result = joinResult.GroupBy(x => x.Foo.Id).Select(x => new
{
Id = x.Key,
Name = x.Max(r => r.Bar)
}).ToList();
}
This query will, as expected, yield the following SQL:
SELECT [foo].[Id], [foo].[BarId], [foo].[Type], [bar].[Name] AS [Bar]
FROM [Foos] AS [foo]
LEFT JOIN [Bars] AS [bar] ON ([foo].[BarId] = [bar].[Id]) AND ([foo].[Type] = N'Bar')
ORDER BY [foo].[Id]
However if we define the type:
public class ConditionalJoin
{
public int Key { get; set; }
public string PropName { get; set; }
}
...and then modify the LINQ query:
using (var ctx = new TestDbContext())
{
var joinResult = ctx.Foos.GroupJoin(
ctx.Bars,
foo => new ConditionalJoin { Key = foo.BarId, PropName = foo.Type }, // <-- changed
bar => new ConditionalJoin { Key = bar.Id, PropName = "Bar" }, // <-- changed
(foo, bars) => new
{
Foo = foo,
Bars = bars
})
.SelectMany(
x => x.Bars.DefaultIfEmpty(),
(foo, bar) => new
{
Foo = foo.Foo,
Bar = bar.Name
});
var result = joinResult.GroupBy(x => x.Foo.Id).Select(x => new
{
Id = x.Key,
Name = x.Max(r => r.Bar)
}).ToList();
}
Then the produced SQL looks like:
SELECT [foo0].[Id], [foo0].[BarId], [foo0].[Type]
FROM [Foos] AS [foo0]
SELECT [bar0].[Id], [bar0].[Name]
FROM [Bars] AS [bar0]
Why does this happen?