سؤال

في Subsity Simplypository 3.04 ، لا يمكنني أداء أ Contains العملية داخل تعبير Lambda. إليك مثال تافهة:

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

أحصل على رسالة الخطأ:

متغير "X" من مستخدم النوع "المشار إليه من النطاق" ، ولكن لم يتم تعريفه

هل أفتقد شيئًا هنا ، أو لا يدعم الصوت دون دعم Contains في تعبيرات لامدا؟ إذا لم يكن كذلك ، كيف سيتم ذلك؟

هل كانت مفيدة؟

المحلول

لأن أيا من هؤلاء يبدو أنه يعمل ...

x => guids.Contains(x.Guid)
x => guids.Any(y => y == x.Guid)

... نكتب منشئ تعبير Lambda مخصص يولد:

x => x.Id == {id1} OR x.Id == {id2} OR x.Id == {id3}

هذا سيناريو تافهة ، لكنه يوضح كيف GetContainsId<User>(ids, repo) سيجد جميع المستخدمين الذين يعانون من معرف يطابق شيئًا ما في القائمة المقدمة.

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

نصائح أخرى

من المحتمل ألا يكون الصوت دون قادر على تحويل userIds.Contains لأنه غير قادر على ترجمة تلك القائمة إلى شيء يمكن تنفيذه على قاعدة بيانات SQL. من المحتمل أن تضطر إلى اللجوء إلى تعريف أو شرط بشكل واضح:

repo.Find<User>(x => x.Id == 1 || x.Id == 3).ToList();

أنا متأكد من أن هذا سيعمل إذا كنت تستخدم ienumerable بدلاً من القائمة. لذلك يجب أن يعمل التالي:

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();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top