在Linq语句的Where子句中,
var myClasses = (from b in db.MyRecords
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
where (b.Active == 1)
select new { b });
表达式b.Active==1
可以正常工作。但是如果我这样做,
Expression<Func<MyRecords, bool>> filter = my => my.Active == 1;
[更新:由于汉斯的回答,我将其保留为原文,但实际上,我在这里打错了。表达式实际上是使用基础类型,而不是像查询Linq那样由EF生成的复数。我真的有这个,
Expression<Func<MyRecord, bool>> filter = my => my.Active == 1;
]
尝试一下
var myClasses = (from b in db.MyRecords
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
where (filter)
select new { b });
编译器抱怨
无法将查询表达式转换为预期的委托类型,因为某些 块中的返回类型不能隐式转换为 委托返回类型
我对此有很多疑问,但是我不明白为什么它不起作用。我对基本原理有误解,所以我并不是要任何人来编写代码。我想知道Linq想要什么,因此我对Linq有了更好的了解,而不仅仅是使某些事情起作用。例如,这有效
var myClasses = (from b in db.MyRecords.Where(filter)
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
select new { b });
我想知道为什么它在那里起作用,而不是在联接之后的位置起作用。如果我在联接末尾执行“位置”,则编译器仍会知道MyRecords字段,包括Active。
我认为是我想要的一个适当描述,因为它似乎很适合我。
答案 0 :(得分:3)
您的过滤器类型错误,将在第一个示例中应用。蓝色linq语法为您提供了很多魔术,使此查询易于阅读。实际发生的情况是创建一些匿名类型,这些类型包含对您的项目的引用。注意,在where子句中,您也可以使用p
和cse
变量。而且,当您将表达式考虑在内时,您可能会发现它实际上就像这样的Expression<Func<Tuple<MyRecords, People, Courses>>
,它不是元组而是某种匿名类型。
当您要求resharper将蓝色语法转换为方法链时,它会生成如下代码:
(db.MyRecords.Join(
db.People,
b => b.PersonId,
p => p.PersonId,
(b, p) => new {b, p})
.Join(
db.Courses,
t => t.b.CourseId,
cse => cse.CourseId,
(t, cse) => new {t, cse})
.Where(t => (t.t.b.Active == 1))
.Select(t => new {t.t.b}));
实际上,您不能像在蓝色语法中那样使用filter变量:
... join cse in db.Courses on b.CourseId equals cse.CourseId
where (filter)
您将不得不切换到方法调用:
(from b in db.MyRecords
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
select b)
.Where(filter)
现在,仅因为我们将内部查询的大小调整为b
,您就可以应用过滤器了。