为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
桃花长相依 2019-12-06 15:29:25
我还很陌生,Linq而且EF对于如何将Linq中的两个列表链接到实体,我深感困惑。我正在使用数据库优先,并且我有两个表:Person与柱Id和Ability与列Id,PersonId并Value因此,Personclass具有一个ICollection<Ability>,称为AllAbilities。在某些View的ViewModel中,我返回了一个int列表,该列表表示用户为所输入的文本框值Ability.Value(称为)AbilitiesInput。我的需求很简单,在Controller中,我必须调用一个查询,该查询将执行以下操作: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,尝试使用A Select创建一个新对象,也尝试使用IndexOf或FindIndex获取没有foreach的索引...如果有人能解释我如何实现这一简单目标,我将非常高兴。非常感谢。
查看完整描述

3 回答

?
繁花不似锦

TA贡献1851条经验 获得超4个赞

我是很新,Linq和EF


您很不走运,因为“简单的事情”在LINQ to Objects中相对容易,但是在LINQ to Entities中却相当困难(几乎不可能)。


为了以某种方式解决它,您需要手动构建LINQ to Entitiescompatible Expression。


首先,您需要一些帮助程序来构建表达谓词。PredicateBuilder是一个流行的选择,但它不会产生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);

        }

    }

}

其次,在控制器中为这样的单个条件定义一个辅助方法


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

}

最后,构建过滤器并将其传递给GetAll方法:


var filter = PredicateUtils.Null<Person>();

for (int i = 0; i < AbilitiesInput.Count; i++)

    filter = filter.And(AbilityFilter(i, AbilitiesInput[i]));

GetAll(filter);

使用的技术绝对不是新手,但我认为没有简单的方法可以解决该特定问题。


查看完整回答
反对 回复 2019-12-06
?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

不知道我是否正确,但是下面的代码可能有助于获得正确的解决方案。使用(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; }

    }

}


查看完整回答
反对 回复 2019-12-06
?
侃侃尔雅

TA贡献1801条经验 获得超15个赞

非常感谢您的答复,但是为了在查询的where子句中使用它,我需要一个布尔值而不是List<Ability> results。我如何将其更改为布尔值?我尝试用替换WhereAllAll似乎无法处理(x, i)

查看完整回答
反对 回复 2019-12-06
  • 3 回答
  • 0 关注
  • 388 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信