2017-06-21 54 views
0

我使用EF v5/6。我想知道如何在用户尝试通过UI动态添加搜索过滤器时动态地构建Where子句。实体框架6:针对DB动态构建搜索子句

看到UI第一 enter image description here

现在最终用户将通过上述UI添加多达过滤器,并尝试搜索数据库。

我尝试搜索谷歌的一些解决方案,结果我可以添加多个搜索到我的分贝表与EF和我发现很少。这里是几个环节

https://stackoverflow.com/a/5595591/6188148

https://stackoverflow.com/a/24824290/6188148

上述引导线是艰难的,我听不懂。所以我看起来很容易。

此链接位接近我的要求https://stackoverflow.com/a/16646241/6188148但仍然我不知道如何自定义他们的代码用于我的方案。

所以我的要求任何人都可以帮助一个小样本代码,帮助我完成任务。

+0

考虑到性能先进的搜索这样的,我会建议使用专用产品,如[Elasticsearch(https://www.elastic.co/),我花了几天时间试图做类似的东西在里面的EF只会发现它在较大的数据上执行得有多糟糕。 – uk2k05

+0

Elasticsearch可以使用EF从sql server中获取数据.....我不知道。 –

回答

3

我假设你可以在GUI中的每一行建立一个子条件。例如,第一线将类似于

string userInputName = "john"; 
Expression<Func<Person, bool>> condition1 = person => person.Name.Contains(userInputName); 

而且可以用作

var selection = db.Persons.Where(condition1).ToList(); 

为多个子的条件下,and仅仅是一个Where条件级联:

var conditions = new List<Expression<Func<Person, bool>>>() { condition1, condition2, ... }; 

IQueryable<Person> query = db.Persons; 
foreach (var condition in conditions) 
{ 
    query = query.Where(condition); 
} 
var selection = query.ToList(); 

小技巧部分与or条件。假设你已经将你的条件标准化为and替代条件(disjunctive normal form),那么你可以得到多组有效的结果。为了简便起见,我把它在这里2组,但它可以推广的方式相同and条件:

or可以通过子查询的Union操作来表示。

var conditions1 = new List<Expression<Func<Person, bool>>>() { condition1, condition2, ... }; 
IQueryable<Person> query1 = // see above construction logic for 'and' conditions 
var conditions2 = new List<Expression<Func<Person, bool>>>() { condition5, condition6, ... }; 
IQueryable<Person> query2 = // see above construction logic for 'and' conditions 

IQueryable<Person> query = query1.Union(query2); 
var selection = query.ToList(); 

最后几句话:考虑使用一些建立的过滤器/搜索框架来代替。这种方法可能既不是最漂亮也不是最快的。


按照要求,一个小例子与一些存储器内数据。请注意,这并不等于Linq-to-entities的100%。例如,字符串比较将以不同的方式处理大小写,并且SQL可能不允许任何类型的条件。

public enum TypeOfContact 
{ 
    Unknown, 
    Email 
} 
public class Person 
{ 
    public string Name { get; set; } 

    public DateTime Birth { get; set; } 

    public TypeOfContact ContactType { get; set; } 

    public string ContactValue { get; set; } 
} 

public class Program 
{ 
    static void Main(string[] args) 
    { 
     // test data to simulate a database table 
     var Persons = new List<Person> 
     { 
      // + All conditions met 
      new Person { Name = "john doe", Birth = new DateTime(2011, 1, 1), ContactType = TypeOfContact.Email, ContactValue = "[email protected]" }, 
      // - Not in result 
      new Person { Name = "danny doe", Birth = new DateTime(2012, 1, 1), ContactType = TypeOfContact.Email, ContactValue = "[email protected]" }, 
      // + Name contains john 
      new Person { Name = "john doe", Birth = new DateTime(2013, 1, 1), ContactType = TypeOfContact.Unknown, ContactValue = "" }, 
      // + Birth, ContactType and ContactValue correct 
      new Person { Name = "justin", Birth = new DateTime(2014, 1, 1), ContactType = TypeOfContact.Email, ContactValue = "[email protected]" }, 
      // - Not in result because Name and Birth are wrong 
      new Person { Name = "jonny", Birth = new DateTime(1979, 1, 1), ContactType = TypeOfContact.Email, ContactValue = "[email protected]" }, 
      // - Not in result 
      new Person { Name = "jenny doe", Birth = new DateTime(2016, 1, 1), ContactType = TypeOfContact.Unknown, ContactValue = "" }, 
     }.AsQueryable(); 

     // single-line-conditions 
     Expression<Func<Person, bool>> c1 = p => p.Name.Contains("john"); 
     Expression<Func<Person, bool>> c2 = p => p.Birth.Date >= new DateTime(1980, 1, 1); 
     Expression<Func<Person, bool>> c3 = p => p.ContactType == TypeOfContact.Email; 
     Expression<Func<Person, bool>> c4 = p => p.ContactValue.EndsWith("@email.com"); 

     // DNF groups: outer list = or; inner list = and 
     // c1 or (c2 and c3 and c4) 
     var conditionList = new List<List<Expression<Func<Person, bool>>>> 
     { 
      new List<Expression<Func<Person, bool>>> 
      { 
       c1, 
      }, 
      new List<Expression<Func<Person, bool>>> 
      { 
       c2, 
       c3, 
       c4, 
      }, 
     }; 

     var andSubResults = new List<IQueryable<Person>>(); 
     foreach (var andQueries in conditionList) 
     { 
      var subQuery = Persons; 
      foreach (var andQuery in andQueries) 
      { 
       subQuery = subQuery.Where(andQuery); 
      } 
      andSubResults.Add(subQuery); 
     } 
     var query = andSubResults.FirstOrDefault(); 
     foreach (var subResult in andSubResults.Skip(1)) 
     { 
      query = query.Union(subResult); 
     } 
     var selection = query.ToList(); 
     // just check the result in debugger 
    } 
} 
+0

我想只是一个小的请求,你可以给我一个小的但充分的工作示例,如果可能的话,在这个问题上。谢谢 –

+0

我想去你的例子中突出显示的条件迭代循环。 说这一个.......'var conditions = new List >>(){condition1,condition2,...}; IQueryable query = db.Persons; foreach(var condition in conditions) { query = query.Where(condition); } var selection = query.ToList();' –

+2

@MonojitSarkar *小而全的工作示例*将包括设置一个实际的数据库,否则它只是一个内存中的例子,它与linq-对实体。我觉得这会超出答案的范围。我仍然会写一个小内存的例子。 – grek40