using ExpressiveSharp.Mapping;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
// Bug: [ExpressiveProperty] stub using SelectMany(x => x.NavCollection) where
// NavCollection is ICollection<T> causes EF Core to throw at runtime.
//
// The generator rewrites the lambda to (x => (IEnumerable<T>)x.NavCollection),
// and EF Core cannot translate the explicit cast.
//
// Workaround: write SelectMany(x => x.NavCollection.Select(y => y)) so the
// result is already IEnumerable<T> and no cast is inserted.
using var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();
using var db = new TestDbContext(connection);
db.Database.EnsureCreated();
db.Grandparents.Add(new Grandparent
{
Parents =
[
new Parent
{
Children = [new Child { Value = 1 }, new Child { Value = 2 }]
},
new Parent
{
Children = [new Child { Value = 3 }]
}
]
});
db.SaveChanges();
var results = db.Grandparents
.Select(gp => gp.GrandChildren)
.ToList();
foreach (var group in results)
foreach (var child in group)
Console.WriteLine(child.Value);
var resultsFail = db.Grandparents
.Select(gp => gp.GrandChildrenFail)
.ToList();
foreach (var group in resultsFail)
foreach (var child in group)
Console.WriteLine(child.Value);
internal class TestDbContext(SqliteConnection connection) : DbContext
{
public DbSet<Grandparent> Grandparents => Set<Grandparent>();
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite(connection).UseExpressives();
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public int Value { get; set; }
}
public class Parent
{
public int Id { get; set; }
public int GrandparentId { get; set; }
public virtual ICollection<Child> Children { get; set; } = [];
}
public partial class Grandparent
{
public int Id { get; set; }
public virtual ICollection<Parent> Parents { get; set; } = [];
// FAILS: generator emits SelectMany(p => (IEnumerable<Child>)p.Children) — EF can't translate.
[ExpressiveProperty("GrandChildrenFail")]
private IEnumerable<Child> FailsExpr =>
Parents.SelectMany(p => p.Children);
// WORKS: .Select(c => c) inside SelectMany keeps type as IEnumerable<Child>, no cast needed.
[ExpressiveProperty("GrandChildren")]
private IEnumerable<Child> WorksExpr =>
Parents.SelectMany(p => p.Children.Select(c => c));
}