Lambda enthält in SimpleRepository.Find
-
03-10-2019 - |
Frage
In SubSonic 3.04 des SimpleRepository, kann ich nicht scheinen, einen Contains
Betrieb in einem Lambda-Ausdruck auszuführen. Hier ist ein einfaches Beispiel:
SimpleRepository repo = new SimpleRepository("ConnectionString");
List<int> userIds = new List<int>();
userIds.Add(1);
userIds.Add(3);
List<User> users = repo.Find<User>(x => userIds.Contains(x.Id)).ToList();
ich die Fehlermeldung:
Variable 'x' vom Typ 'User' von Umfang verwiesen wird '', aber es ist nicht definiert
Bin ich hier fehlt etwas, oder hat SubSonic nicht Contains
in Lambda-Ausdrücke unterstützen? Wenn nicht, würde, wie dies geschehen?
Lösung
Da beides nicht zu funktionieren scheint ...
x => guids.Contains(x.Guid)
x => guids.Any(y => y == x.Guid)
... schreiben wir einen benutzerdefinierte Lambda-Ausdruck Builder, erzeugt:
x => x.Id == {id1} OR x.Id == {id2} OR x.Id == {id3}
Dies ist eine triviale Szenario, aber zeigt, wie GetContainsId<User>(ids, repo)
alle Benutzer mit einer ID finden, die etwas in der mitgelieferten Liste übereinstimmt.
public List<T> GetContainsId<T>(List<int> ids, SimpleRepository repo)
where T : Record, new() // `Record` is a base class with property Id
{
ParameterExpression x = Expression.Parameter(typeof(T), "x");
LambdaExpression expr;
if (ids.Count == 0)
{
expr = Expression.Lambda(LambdaExpression.Constant(false), x);
}
else
{
expr = Expression.Lambda(BuildEqual(x, ids.ToArray()), x);
}
return repo.Find<T>((Expression<Func<T,bool>>)expr).ToList();
}
private BinaryExpression BuildEqual(ParameterExpression x, int id)
{
MemberExpression left = Expression.Property(x, "Id");
ConstantExpression right = Expression.Constant(id);
return Expression.Equal(left, right);
}
private BinaryExpression BuildEqual(ParameterExpression x, int[] ids, int pos = 0)
{
int id = ids[pos];
pos++;
if (pos == ids.Length)
{
return BuildEqual(x, id);
}
return Expression.OrElse(BuildEqual(x, ids, pos), BuildEqual(x, id));
}
Andere Tipps
Subsonic ist wahrscheinlich nicht in der Lage, die userIds.Contains
zu konvertieren, weil sie nicht in der Lage ist, diese Liste in etwas zu übersetzen, es auf einer SQL-Datenbank ausführen kann. Sie werden wahrscheinlich ein oder Zustand zurückgreifen müssen in explictely definieren:
repo.Find<User>(x => x.Id == 1 || x.Id == 3).ToList();
Ich bin ziemlich sicher, dass dies funktionieren wird, wenn Sie eine IEnumerable verwenden statt einer Liste. So sollten folgende Arbeiten:
SimpleRepository repo = new SimpleRepository("ConnectionString");
IEnumerable<int> userIds = new List<int>();
userIds.Add(1);
userIds.Add(3);
List<User> users = repo.Find<User>(x => userIds.Contains(x.Id)).ToList();