在linq中的两个列表之间build立一个链接到实体where子句

我对LinqEF相当Linq ,而且我被困在如何将Linq中的两个列表链接到实体。

我使用数据库优先,我有两个表:

Person ,与列Id

Ability ,与列IdPersonIdValue

因此, Person类具有ICollection<Ability> ,称为AllAbilities

在某些视图的ViewModel中,我得到一个int列表,代表用户为Ability.Valueinput的名为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 .. 。

如果有人能解释我怎么能做到这件简单的事情,我会如此,真高兴。
非常感谢。

我对LinqEF相当Linq

你不走运,因为“这个简单的东西”在LINQ to Objects中比较容易,但是在LINQ to Entities中很难(几乎不可能)。

为了以某种方式解决它,你需要手动build立LINQ to Entities兼容的Expression

首先,您需要一些助手来构buildexpression式谓词。 PredicateBuilder是一个stream行的select,但是它不会产生与EF兼容的expression式,并且需要存储库中的LinqKitAsExpandable 。 所以我使用下面的类似的帮助程序,但是生成最终的兼容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; } } }