Je suis assez nouveau pour Linq
et EF
et je ne comprends pas comment je pourrais relier deux listes de Linq à des entités.
J’utilise Database First et j’ai deux tables:
Person
, avec Id
colonne
et
Ability
, avec les colonnes Id
, PersonId
et Value
Ainsi, la classe Person
a une ICollection
, appelée AllAbilities
.
Dans le ViewModel de certaines vues, je récupère une liste d’int, représentant les valeurs des Ability.Value
de Ability.Value
entrées par l’utilisateur pour Ability.Value
, appelé AbilitiesInput
. Mon besoin est simple, dans le contrôleur je dois appeler une requête qui ferait ce qui suit:
GetAll(person => for(i = 0; i AbilitiesInput[i] } )
Où la méthode GetAll
ressemble à cela dans mon GetAll
générique:
public virtual async Task<List> GetAll( Expression<Func> wherePredicate = null { ... }
Pour résumer, j’ai juste besoin d’un booléen qui puisse vérifier si chaque AllAbilities[i]
est supérieur à AbilitiesInput[i]
, mais rien de ce que j’ai essayé n’a fonctionné.
J’ai essayé de modifier AbilitiesInput
to List
ou List
mais une erreur s’est List
No mapping exists
, j’ai essayé d’utiliser un FindIndex
Select
pour créer un nouvel object, FindIndex
également essayé d’utiliser IndexOf
ou FindIndex
pour obtenir un index sans foreach .. .
Si quelqu’un pouvait m’expliquer comment je pouvais réaliser cette chose simple, je serais si heureux.
Merci beaucoup.
Je suis assez nouveau pour
Linq
etEF
Vous n’avez pas de chance, car “cette chose simple” est relativement facile dans LINQ to Objects, mais assez difficile (voire impossible) dans LINQ to Entities.
Pour le résoudre, vous devez créer manuellement une Expression
compatible LINQ to Entities.
Premièrement, vous aurez besoin d’aides pour la construction de prédicats d’expression. PredicateBuilder est un choix LinqKit
, mais il ne produit pas d’expressions compatibles EF et requirejs LinqKit
et AsExpandable
à l’intérieur du référentiel. J’utilise donc les aides ci-dessous qui sont similaires, mais produisent des expressions compatibles finales:
public static class PredicateUtils { sealed class Predicate { public static readonly Expression> True = item => true; public static readonly Expression> False = item => false; } public static Expression> Null () { return null; } public static Expression> True () { return Predicate .True; } public static Expression> False () { return Predicate .False; } public static Expression> And (this Expression> left, Expression> right) { if (Equals(left, right)) return left; if (left == null || Equals(left, True ())) return right; if (right == null || Equals(right, True ())) return left; if (Equals(left, False ()) || Equals(right, False ())) return False (); var body = Expression.AndAlso(left.Body, right.Body.Replace(right.Parameters[0], left.Parameters[0])); return Expression.Lambda>(body, left.Parameters); } public static Expression> Or (this Expression> left, Expression> right) { if (Equals(left, right)) return left; if (left == null || Equals(left, False ())) return right; if (right == null || Equals(right, False ())) return left; if (Equals(left, True ()) || Equals(right, True ())) return True (); var body = Expression.OrElse(left.Body, right.Body.Replace(right.Parameters[0], left.Parameters[0])); return Expression.Lambda>(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); } } }
Deuxièmement, définissez une méthode d’assistance dans votre contrôleur pour un critère unique comme celui-ci.
static Expression> AbilityFilter(int index, int value) { return p => p.AllAbilities.OrderBy(a => a.Id).Skip(index).Take(1).Any(a => a.Value > value); }
Enfin, construisez le filtre et transmettez-le à la méthode GetAll
:
var filter = PredicateUtils.Null(); for (int i = 0; i < AbilitiesInput.Count; i++) filter = filter.And(AbilityFilter(i, AbilitiesInput[i])); GetAll(filter);
Les techniques utilisées ne sont certainement pas pour un novice, mais je ne vois pas de moyen simple de résoudre ce problème particulier.
Je ne sais pas si j’ai bien compris, mais le code ci-dessous peut aider à trouver la solution correcte Utiliser (x, i) énumérera la collection et obtiendra un index afin que vous puissiez comparer les deux collections.
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 AbilitiesInput = null; public Form1() { InitializeComponent(); AbilitiesInput = new List () { textBox1, textBox2, textBox3, textBox4 }; Person person = new Person(); List results = person.AllAbilities.Where((x, i) => x.Value > int.Parse(AbilitiesInput[i].Text)).ToList(); } } public class Person { public int Id { get; set; } public List AllAbilities { get; set; } public Person() { AllAbilities = new List (); } } public class Ability { public int Id { get; set;} public int PersonId { get; set; } public int Value { get; set; } } }