在linq中的两个列表之间build立一个链接到实体where子句
我对Linq
和EF
相当Linq
,而且我被困在如何将Linq中的两个列表链接到实体。
我使用数据库优先,我有两个表:
Person
,与列Id
和
Ability
,与列Id
, PersonId
和Value
因此, Person
类具有ICollection<Ability>
,称为AllAbilities
。
在某些视图的ViewModel中,我得到一个int列表,代表用户为Ability.Value
input的名为AbilitiesInput
文本框值。 我的需求很简单,在控制器中,我必须调用一个查询来执行以下操作:
GetAll(person => for(i = 0; i < AbilitiesCount; i++) { person.AllAbilities[i] > AbilitiesInput[i] } )
GetAll
方法看起来像我的通用回购:
public virtual async Task<List<TEntity>> GetAll( Expression<Func<TEntity, bool>> wherePredicate = null { ... }
要恢复,我只需要一个布尔值,可以检查AllAbilities[i]
是否比AbilitiesInput[i]
更高,但是我没有尝试过。
我试图改变AbilitiesInput
List<KeyValuePair>
或List<Tuple>
但得到一个错误说, No mapping exists
,试图使用一个Select
创build一个新的对象,也试图使用索引或FindIndex
获取索引没有foreach .. 。
如果有人能解释我怎么能做到这件简单的事情,我会如此,真高兴。
非常感谢。
我对
Linq
和EF
相当Linq
你不走运,因为“这个简单的东西”在LINQ to Objects中比较容易,但是在LINQ to Entities中很难(几乎不可能)。
为了以某种方式解决它,你需要手动build立LINQ to Entities兼容的Expression
。
首先,您需要一些助手来构buildexpression式谓词。 PredicateBuilder是一个stream行的select,但是它不会产生与EF兼容的expression式,并且需要存储库中的LinqKit
和AsExpandable
。 所以我使用下面的类似的帮助程序,但是生成最终的兼容expression式:
public static class PredicateUtils { sealed class Predicate<T> { public static readonly Expression<Func<T, bool>> True = item => true; public static readonly Expression<Func<T, bool>> False = item => false; } public static Expression<Func<T, bool>> Null<T>() { return null; } public static Expression<Func<T, bool>> True<T>() { return Predicate<T>.True; } public static Expression<Func<T, bool>> False<T>() { return Predicate<T>.False; } public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right) { if (Equals(left, right)) return left; if (left == null || Equals(left, True<T>())) return right; if (right == null || Equals(right, True<T>())) return left; if (Equals(left, False<T>()) || Equals(right, False<T>())) return False<T>(); var body = Expression.AndAlso(left.Body, right.Body.Replace(right.Parameters[0], left.Parameters[0])); return Expression.Lambda<Func<T, bool>>(body, left.Parameters); } public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right) { if (Equals(left, right)) return left; if (left == null || Equals(left, False<T>())) return right; if (right == null || Equals(right, False<T>())) return left; if (Equals(left, True<T>()) || Equals(right, True<T>())) return True<T>(); var body = Expression.OrElse(left.Body, right.Body.Replace(right.Parameters[0], left.Parameters[0])); return Expression.Lambda<Func<T, bool>>(body, left.Parameters); } static Expression Replace(this Expression expression, Expression source, Expression target) { return new ExpressionReplacer { Source = source, Target = target }.Visit(expression); } class ExpressionReplacer : ExpressionVisitor { public Expression Source; public Expression Target; public override Expression Visit(Expression node) { return node == Source ? Target : base.Visit(node); } } }
其次,在你的控制器中为这样一个标准定义一个辅助方法
static Expression<Func<Person, bool>> AbilityFilter(int index, int value) { return p => p.AllAbilities.OrderBy(a => a.Id).Skip(index).Take(1).Any(a => a.Value > value); }
最后,构buildfilter并将其传递给GetAll
方法:
var filter = PredicateUtils.Null<Person>(); for (int i = 0; i < AbilitiesInput.Count; i++) filter = filter.And(AbilityFilter(i, AbilitiesInput[i])); GetAll(filter);
所使用的技术绝对不是新手,但我没有看到解决这个问题的简单方法。
不知道我是否正确,但下面的代码可能有助于得到正确的解决scheme。 使用(x,i)将通过集合枚举并获得一个索引,以便您可以比较这两个集合。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { List<TextBox> AbilitiesInput = null; public Form1() { InitializeComponent(); AbilitiesInput = new List<TextBox>() { textBox1, textBox2, textBox3, textBox4 }; Person person = new Person(); List<Ability> results = person.AllAbilities.Where((x, i) => x.Value > int.Parse(AbilitiesInput[i].Text)).ToList(); } } public class Person { public int Id { get; set; } public List<Ability> AllAbilities { get; set; } public Person() { AllAbilities = new List<Ability>(); } } public class Ability { public int Id { get; set;} public int PersonId { get; set; } public int Value { get; set; } } }