سؤال

نحن نعمل على عارض السجل.سيكون للاستخدام خيار التصفية حسب المستخدم، والخطورة، وما إلى ذلك.في أيام Sql، كنت سأضيف إلى سلسلة الاستعلام، لكني أريد أن أفعل ذلك باستخدام Linq.كيف يمكنني إضافة عبارات حيث بشكل مشروط؟

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

المحلول

إذا كنت تريد التصفية فقط إذا تم تمرير معايير معينة، فافعل شيئًا كهذا

var logs = from log in context.Logs
           select log;

if (filterBySeverity)
    logs = logs.Where(p => p.Severity == severity);

if (filterByUser)
    logs = logs.Where(p => p.User == user);

سيؤدي القيام بذلك بهذه الطريقة إلى السماح لشجرة التعبير الخاصة بك بأن تكون بالضبط ما تريده.بهذه الطريقة سيكون SQL الذي تم إنشاؤه هو ما تحتاجه بالضبط وليس أقل من ذلك.

نصائح أخرى

إذا كنت بحاجة إلى تصفية القاعدة على قائمة/مصفوفة، فاستخدم ما يلي:

    public List<Data> GetData(List<string> Numbers, List<string> Letters)
    {
        if (Numbers == null)
            Numbers = new List<string>();

        if (Letters == null)
            Letters = new List<string>();

        var q = from d in database.table
                where (Numbers.Count == 0 || Numbers.Contains(d.Number))
                where (Letters.Count == 0 || Letters.Contains(d.Letter))
                select new Data
                {
                    Number = d.Number,
                    Letter = d.Letter,
                };
        return q.ToList();

    }

لقد انتهيت من استخدام إجابة مشابهة لإجابة دارين، ولكن باستخدام واجهة IQueryable:

IQueryable<Log> matches = m_Locator.Logs;

// Users filter
if (usersFilter)
    matches = matches.Where(l => l.UserName == comboBoxUsers.Text);

 // Severity filter
 if (severityFilter)
     matches = matches.Where(l => l.Severity == comboBoxSeverity.Text);

 Logs = (from log in matches
         orderby log.EventTime descending
         select log).ToList();

يؤدي ذلك إلى إنشاء الاستعلام قبل الوصول إلى قاعدة البيانات.لن يتم تشغيل الأمر حتى .ToList() في النهاية.

عندما يتعلق الأمر باللينك الشرطي، فأنا معجب جدًا بنمط المرشحات والأنابيب.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/

تقوم بشكل أساسي بإنشاء طريقة ملحقة لكل حالة مرشح تأخذ IQueryable ومعلمة.

public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
    return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}

هناك خيار آخر يتمثل في استخدام شيء مثل PredicateBuilder الذي تمت مناقشته هنا.يسمح لك بكتابة التعليمات البرمجية مثل ما يلي:

var newKids  = Product.ContainsInDescription ("BlackBerry", "iPhone");

var classics = Product.ContainsInDescription ("Nokia", "Ericsson")
                  .And (Product.IsSelling());

var query = from p in Data.Products.Where (newKids.Or (classics))
            select p;

لاحظ أن لدي هذا فقط للعمل مع Linq 2 SQL.لا يقوم EntityFramework بتنفيذ Expression.Invoc المطلوب لكي تعمل هذه الطريقة.لدي سؤال بخصوص هذه المسألة هنا.

فعل هذا:

bool lastNameSearch = true/false; // depending if they want to search by last name,

وجود هذا في where إفادة:

where (lastNameSearch && name.LastNameSearch == "smith")

يعني أنه عند إنشاء الاستعلام النهائي، إذا lastNameSearch يكون false سيقوم الاستعلام بحذف أي SQL للبحث عن الاسم الأخير بشكل كامل.

لقد قمت بحل هذه المشكلة باستخدام طريقة تمديد للسماح بتمكين LINQ بشكل مشروط في منتصف التعبير بطلاقة.هذا يلغي الحاجة إلى تقسيم التعبير مع if صياغات.

.If() طريقة التمديد:

public static IQueryable<TSource> If<TSource>(
        this IQueryable<TSource> source,
        bool condition,
        Func<IQueryable<TSource>, IQueryable<TSource>> branch)
    {
        return condition ? source : branch(source);
    }

هذا يسمح لك بالقيام بذلك:

return context.Logs
     .If(filterBySeverity, q => q.Where(p => p.Severity == severity))
     .If(filterByUser, q => q.Where(p => p.User == user))
     .ToList();

وهنا أيضا IEnumerable<T> الإصدار الذي سيتعامل مع معظم تعبيرات LINQ الأخرى:

public static IEnumerable<TSource> If<TSource>(
    this IEnumerable<TSource> source,
    bool condition,
    Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
    {
        return condition ? source : branch(source);
    }

إنه ليس أجمل شيء ولكن يمكنك استخدام تعبير لامدا وتمرير شروطك اختياريًا.في TSQL أقوم بالكثير مما يلي لجعل المعلمات اختيارية:

حيث الحقل = @FieldVar أو @FieldVar فارغ

يمكنك تكرار نفس النمط باستخدام لامدا التالية (مثال للتحقق من المصادقة):

MyDataContext db = new MyDataContext();

باطلة RunQuery (سلسلة param1، سلسلة param2، int؟المعلمة 3) {

Func checkUser = المستخدم =>

((param1.Length > 0)؟user.Param1 == param1 :1 == 1) &&

((param2.Length > 0)؟user.Param2 == param2 :1 == 1) &&

((param3 != فارغة)؟user.Param3 == param3 :1 == 1)؛

User FoundUser = db.Users.SingleOrDefault(checkUser);

}

كان لدي متطلب مماثل مؤخرًا ووجدت هذا في النهاية في MSDN.عينات CSharp لبرنامج Visual Studio 2008

تسمح لك الفئات المضمنة في نموذج DynamicQuery للتنزيل بإنشاء استعلامات ديناميكية في وقت التشغيل بالتنسيق التالي:

var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");

باستخدام هذا يمكنك إنشاء سلسلة استعلام ديناميكيًا في وقت التشغيل وتمريرها إلى طريقة Where() :

string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; 
var q = from c in db.Customers.Where(queryString, null)
        orderby c.CompanyName
        select c;

ما عليك سوى استخدام عامل التشغيل && الخاص بـ C#:

var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")

يحرر:آه، بحاجة إلى قراءة أكثر بعناية.أردت أن تعرف كيف بشروط إضافة بنود إضافية.في هذه الحالة، ليس لدي أي فكرة.:) ما سأفعله على الأرجح هو مجرد إعداد العديد من الاستعلامات وتنفيذ الاستعلام الصحيح، اعتمادًا على ما احتاجه في النهاية.

يمكنك استخدام طريقة خارجية:

var results =
    from rec in GetSomeRecs()
    where ConditionalCheck(rec)
    select rec;

...

bool ConditionalCheck( typeofRec input ) {
    ...
}

قد ينجح هذا، لكن لا يمكن تقسيمه إلى أشجار تعبير، مما يعني أن Linq to SQL سيقوم بتشغيل رمز التحقق مقابل كل سجل.

بدلاً عن ذلك:

var results =
    from rec in GetSomeRecs()
    where 
        (!filterBySeverity || rec.Severity == severity) &&
        (!filterByUser|| rec.User == user)
    select rec;

قد ينجح ذلك في أشجار التعبير، مما يعني أنه سيتم تحسين Linq إلى SQL.

حسنًا، ما اعتقدته هو أنه يمكنك وضع شروط التصفية في قائمة عامة من المسندات:

    var list = new List<string> { "me", "you", "meyou", "mow" };

    var predicates = new List<Predicate<string>>();

    predicates.Add(i => i.Contains("me"));
    predicates.Add(i => i.EndsWith("w"));

    var results = new List<string>();

    foreach (var p in predicates)
        results.AddRange(from i in list where p.Invoke(i) select i);               

وينتج عن ذلك قائمة تحتوي على "me" و"meyou" و"mow".

يمكنك تحسين ذلك عن طريق إجراء عملية البحث باستخدام المسندات في وظيفة مختلفة تمامًا تمثل جميع المسندات.

يمكنك إنشاء واستخدام طريقة الامتداد هذه

public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate)
{
    return isToExecute ? source.Where(predicate) : source;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top