我假设你可以在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
}
}
考虑到性能先进的搜索这样的,我会建议使用专用产品,如[Elasticsearch(https://www.elastic.co/),我花了几天时间试图做类似的东西在里面的EF只会发现它在较大的数据上执行得有多糟糕。 – uk2k05
Elasticsearch可以使用EF从sql server中获取数据.....我不知道。 –