I have stumbled upon a riddle which I can’t explain, maybe someone here will be able to.
Here is a (rather lengthy but complete) code snippet:
public class Foo
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Foo> InnerFoo { get; set; }
}
public class AppContext : DbContext
{
public IDbSet<Foo> Foos { get; set; }
}
public class Initializer : DropCreateDatabaseAlways<AppContext>
{
protected override void Seed(AppContext context)
{
var list = new List<Foo>
{
new Foo {Name = "one", InnerFoo = new List<Foo>{new Foo {Name = "Four"}}},
new Foo {Name = "two"},
new Foo {Name = "three"},
};
list.ForEach(f => context.Foos.Add(f));
}
}
public class Filter
{
public static Expression<Func<Foo, bool>> GetPredicate()
{
return p => p.Name != null && p.Name.Length > 3;
}
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new Initializer());
using (var ctx = new AppContext())
{
var predicate = Filter.GetPredicate();
var list = ctx.Foos.Where(f => f.InnerFoo.AsQueryable().Where(predicate).Count() > 0).ToList(); // this works
// var list = ctx.Foos.Where(f => f.InnerFoo.AsQueryable().Where(Filter.GetPredicate()).Count() > 0).ToList(); // this doesn't
foreach (var s in list)
{
Console.WriteLine(s.Name);
}
}
}
}
The line that’s commented out doesn’t work – throws an exception at runtime – “Internal .NET Framework Data Provider error 1025.”. I’m using EntityFramework.4.1.10715.0
Can anyone tell me why?
Side question: I’m looking for a way to keep filtering expressions that are used in several different classes.
The problem is that your inner
Whereis already within the context of an “outerWhere” onctx.Foos– so the call toFilter.GetPredicate()ends up as part of the expression tree, and the Entity Framework has no idea what it means or how to translate it into SQL.That’s why it’s happening… I’m not sure of the best solution right now though, unless you can extract the predicate into a separate variable where you need it.
(As an aside, it’s generally more expressive to use
Any(...)than...Count() > 0– and in LINQ to Objects it can make a huge difference.)