C# 在linq to entities where子句中的两个列表之间建立链接

C# 在linq to entities where子句中的两个列表之间建立链接,c#,entity-framework,linq,C#,Entity Framework,Linq,我对Linq和EF非常陌生,我一直在考虑如何将Linq中的两个列表链接到实体 我首先使用数据库,我有两个表: Person,带有列Id 和 能力,带有列Id、PersonId和Value 因此,Person类有一个ICollection,称为AllAbilities 在某个视图的ViewModel中,我得到一个int列表,表示用户为Ability.Value输入的文本框值,称为abilitieInput。 我的需求很简单,在控制器中,我必须调用一个查询,该查询将执行以下操作: GetAll(pe

我对
Linq
EF
非常陌生,我一直在考虑如何将Linq中的两个列表链接到实体

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

Person
,带有列
Id


能力
,带有列
Id
PersonId
Value

因此,
Person
类有一个
ICollection
,称为
AllAbilities

在某个视图的ViewModel中,我得到一个int列表,表示用户为
Ability.Value
输入的文本框值,称为
abilitieInput
。 我的需求很简单,在控制器中,我必须调用一个查询,该查询将执行以下操作:

GetAll(person =>
    for(i = 0; i < AbilitiesCount; i++) { person.AllAbilities[i] > AbilitiesInput[i] }
)
若要继续,我只需要一个布尔值,它可以检查每个
AllAbilities[I]
是否高于
abilitieInput[I]
,但我尝试的结果都不起作用。
我试图将
能力输入
更改为
列表
列表
,但出现了一个错误,错误是
不存在映射
,尝试使用
选择
创建新对象,还尝试使用
索引
查找索引
获取索引,而不使用foreach

如果有人能向我解释我是如何做到这一点的,我会非常非常高兴。

非常感谢。

不确定是否正确,但下面的代码可能有助于获得正确的解决方案。使用(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; }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1
{
公共部分类Form1:Form
{
列表能力输入=空;
公共表格1()
{
初始化组件();
AbilitiesInput=新列表(){textBox1,textBox2,textBox3,textBox4};
Person=新人();
列表结果=person.AllAbilities.Where((x,i)=>x.Value>int.Parse(abilitieInput[i].Text)).ToList();
}
}
公共阶层人士
{
公共int Id{get;set;}
公共列表{get;set;}
公众人士()
{
AllAbilities=新列表();
}
}
公共阶级能力
{
公共int Id{get;set;}
公共int PersonId{get;set;}
公共int值{get;set;}
}
}

不确定是否正确,但下面的代码可能有助于获得正确的解决方案。使用(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; }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1
{
公共部分类Form1:Form
{
列表能力输入=空;
公共表格1()
{
初始化组件();
AbilitiesInput=新列表(){textBox1,textBox2,textBox3,textBox4};
Person=新人();
列表结果=person.AllAbilities.Where((x,i)=>x.Value>int.Parse(abilitieInput[i].Text)).ToList();
}
}
公共阶层人士
{
公共int Id{get;set;}
公共列表{get;set;}
公众人士()
{
AllAbilities=新列表();
}
}
公共阶级能力
{
公共int Id{get;set;}
公共int PersonId{get;set;}
公共int值{get;set;}
}
}
我对
Linq
EF

您运气不好,因为在LINQto对象中“这个简单的事情”相对容易,但在LINQto实体中相当困难(几乎不可能)

为了以某种方式解决这个问题,您需要手动构建与实体兼容的LINQ
表达式

首先,您需要一些帮助程序来构建表达式谓词。是一种流行的选择,但它不生成与EF兼容的表达式,并且需要存储库中的
LinqKit
AsExpandable
。因此,我使用以下类似的帮助程序,但生成最终兼容的表达式:

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);
        }
    }
}
使用的技术绝对不是新手可以使用的,但我看不到解决这个特定问题的简单方法

我对
Linq
EF

您运气不好,因为在LINQto对象中“这个简单的事情”相对容易,但在LINQto实体中相当困难(几乎不可能)

为了以某种方式解决这个问题,您需要手动构建与实体兼容的LINQ
表达式

首先,您需要一些帮助程序来构建表达式谓词。是一种流行的选择,但它不生成与EF兼容的表达式,并且需要存储库中的
LinqKit
AsExpandable
。因此,我使用以下类似的帮助程序,但生成最终兼容的表达式:

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);
        }
    }
}

使用的技术绝对不是新手可以使用的,但我看不到解决这个特定问题的简单方法

能力输入
表示的是
能力
实体的哪些属性-
?不清楚您在搜索什么。返回(1)所有能力大于所有能力输入或(2)任何能力大于任何能力输入或(3)按指数比较的人员?请注意,对于(3),person.Abilities没有定义的顺序。AbilityInput表示用户为当前能力值输入最小值的文本框。因此,如果每个AllAbilities[I]>AbilityInput[I],我需要一个布尔检查。例如,如果AllAbilities[0]AbilityInput[1],我希望返回false。但是如果所有的能力都投入到
var filter = PredicateUtils.Null<Person>();
for (int i = 0; i < AbilitiesInput.Count; i++)
    filter = filter.And(AbilityFilter(i, AbilitiesInput[i]));
GetAll(filter);