我正在尝试将变量从外部上下文传递到使用 LinqKit 的表达式扩展构建的表达式中。
我遇到以下异常:
从范围“”引用的“System.String”类型的变量“__name_0”, 但它没有定义|System.InvalidOperationException:变量 从范围“”引用的“System.String”类型的“__name_0”,但它是 未定义。
public static class EntityProjections
{
public static Expression<Func<Entity, Model>> GetModelProjection(string name)
{
return entity => new Model()
{
Id = entity.Id,
Name = entity.Name != name ? entity.Name : null
};
}
}
string name = "Test";
var models = dbContext.Entities.Select(entity => EntityProjections.GetModelProjection(test).Invoke(entity)).ToList();
是否可以从外部传递这样的变量来构建所需的查询?
这里需要表达式替换。可以通过
ExpandableAttribute
来完成:
public static class EntityProjections
{
[Expandable(nameof(GetModelProjectionImpl))]
public static Model GetModelProjection(Entity entity, string name)
{
throw new NotImplementedException(); // should not call
}
// static function without parameters
private static Expression<Func<Entity, string, Model>> GetModelProjectionImpl()
{
return (entity, name) => new Model()
{
Id = entity.Id,
Name = entity.Name != name ? entity.Name : null
};
}
}
示例调用将是:
string name = "Test";
var models = dbContext.Entities
.Select(entity => EntityProjections.GetModelProjection(entity, name))
.ToList();
虽然我很早之前就接受了答案,但我认为还有一个更简单的解决方案:
public static class EntityProjections
{
public static Expression<Func<Entity, string, Model>> GetModelProjection()
{
return (entity, name) => new Model()
{
Id = entity.Id,
Name = entity.Name != name ? entity.Name : null
};
}
}
string name = "Test";
var models = dbContext.Entities.Select(entity => EntityProjections.GetModelProjection().Invoke(entity, test)).ToList();
这样我们就不必替换表达式了。另外,我们还可以在 GetModelProjection(DbContext dbContext) 中传递 DbContext,调用 EntityProjections.GetModelProjection(dbContext).Invoke(...) 并在投影内进行子查询。这对于表达式替换来说是不可能的,因为 EF 无法翻译它。这就是为什么我更喜欢这个版本。