Entity Framework 4:如何将字符串条件转换为Lambda表达式?

8

我希望能够从客户端接收一个字符串数组的where条件,例如field == value。 创建一个规范对象来接受构造函数中的字符串并输出代表Where子句的lambda表达式将会非常方便。例如,我可以这样做:

var myCondition = new Specification<Product>( myStringArrayOfConditions); 
var myProducts = DB.Products.Where( myCondition);

你如何将 "name == Jujyfruits" 转换为
DB.Products.Where(p => p.name == "JujyFruits")


为什么不能把 lambda 表达式传递给方法,这样就不用传递字符串 .Where("name == Jujyfruits") 了,而是可以传递 .Where(x => x.name == "Jujyfruits")?我真的不知道你想做什么。 - Phill
如果“规范”(where子句)来自客户端,它将以字符串形式呈现。我需要将其转换为EF可以理解的内容,通常是一个lambda表达式。 - Zachary Scott
3个回答

14

您可以使用反射从字符串name获取属性Product.name,并使用LINQ Expression类手动创建lambda表达式。

请注意,以下代码示例仅适用于Equals (==)操作。但是,很容易推广到其他操作(在空格上拆分,解析运算符并选择适当的表达式而不是Expression.Equal)。

    var condition = "name == Jujyfruits";

    // Parse the condition
    var c = condition.Split(new string[] { "==" }, StringSplitOptions.None);
    var propertyName = c[0].Trim();
    var value = c[1].Trim();

    // Create the lambda
    var arg = Expression.Parameter(typeof(Product), "p");
    var property = typeof(Product).GetProperty(propertyName);
    var comparison = Expression.Equal(
        Expression.MakeMemberAccess(arg, property),
        Expression.Constant(value));
    var lambda = Expression.Lambda<Func<Product, bool>>(comparison, arg).Compile();

    // Test
    var prod1 = new Product() { name = "Test" };
    var prod2 = new Product() { name = "Jujyfruits" };
    Console.WriteLine(lambda(prod1));  // outputs False
    Console.WriteLine(lambda(prod2));  // outputs True

关于构造函数的事情:由于 Func<T, TResult> 是 sealed 的,所以您无法从中派生。但是,您可以创建一个 隐式转换运算符,将 Specification<T> 转换为 Func<T, bool>

1
@Dr. Zim:实际上,Products.Where(lambda) 应该就足够了。 - Heinzi
1
如果你要走这条路,请考虑缓存委托(var lambda)。编译表达式树会有相当大的性能损失,你肯定不想在每次搜索查询之前都这样做。 - AnteSim
1
@AnteSim:这取决于您如何定义“合理”。在我的机器上,对上述Lambda进行编译需要约5毫秒。我猜搜索的数据库查询部分会花费更长的时间... - Heinzi
1
@Heinzi:如果他将此代码调整为基于多个属性过滤搜索,会发生什么情况?就目前而言,您的代码很好。但是您需要意识到,如果需要,这是一个优化点。 - AnteSim
@Dr. Zim:感谢您提供的链接,我已将其添加到我的答案中。 - Heinzi
显示剩余5条评论

3
我们最近发现了来自VS2008示例项目的Dynamic LINQ库。它可以完美地将基于字符串的“Where”子句转换为表达式。
这个链接会带你到相关页面:点击这里

它在where子句中肯定使用了一个字符串。这是一个好答案。然而,它会产生一个副作用,即改变数据类型。 - Zachary Scott

0
你需要将搜索词转换为谓词。尝试使用以下内容:
string searchString = "JujyFruits";
Func<Product, bool> search = new Func<Product,bool>(p => p.name == searchString);

return DB.Products.Where(search);

有没有办法避开大的switch语句来测试Product的每个属性的名称?你能否获取Product的“原始”属性列表,针对字段魔术字符串进行测试,并构建一个lambda表达式,其中p.name表示为魔术字符串? - Zachary Scott
1
嗯,我不确定这是否简单。请参阅此问题:https://dev59.com/93RB5IYBdhLWcg3wHkPi - Paul Suart
http://linqspecs.codeplex.com/ 很像你的答案,这强化了你的方法可能是使规范成为一等公民的普遍接受方法。 - Zachary Scott

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接