2010-10-04 152 views
3

我想写一个Linq查询,它提取所有用户的名字或姓氏以字符串列表中的至少一个字符串开头。这用于在消息传递系统中自动完成收件人。Linq to SQL:通过||进行聚合

这是我第一次尝试天真:

var users = UserRepository.ALL() 
foreach (var part in new [] { 'Ha', 'Ho', 'He' }) 
{ 
    string part1 = part; // "Copy" since we're coding lazily 
    users = users.Where(x => x.LastName.StartsWith(part1) || 
          x.FirstName.StartsWith(part1)); 
} 

这不工作,虽然,作为结果变成:

users.Where(a || b).Where(c || d).Where(e || f)... 

...而我想:

users.Where(a || b || c || d || e || f || ...) 

我会如何去做这件事?

回答

0

当然,我应该使用Union ...

IQueryable<User> result = null; 
foreach (var part in terms) 
{ 
    string part1 = part; 
    var q = users.Where(x => x.FirstName.StartsWith(part1) || 
          x.LastName.StartsWith(part1)); 
    result = result == null ? q : result.Union(q); 
} 

使用ReSharper的,这可能变成一个LINQ表达式:

IQueryable<User> result = terms.Select(part1 => 
    users.Where(x => x.FirstName.StartsWith(part1) || 
        x.LastName.StartsWith(part1))) 
     .Aggregate<IQueryable<User>, IQueryable<User>>(
       null, (current, q) => current == null ? q : current.Union(q)); 

...但我可能会去的foreach这次循环。 :)

0

您需要使用2个集合 - 在您的代码中,您正在筛选一个列表...实际上您需要筛选列表的集合 - 而不是已被多次筛选的列表的集合。

一个作为比赛的仓库和其他witin你的循环

var userCollection = new Collection<string>(); 
var users = UserRepository.ALL() 
foreach (var part in new [] { 'Ha', 'Ho', 'He' }) 
{ 
    string part1 = part; // "Copy" since we're coding lazily 
    var matches = users.Where(x => x.LastName.StartsWith(part1) || 
          x.FirstName.StartsWith(part1)); 
    foreach (var i in matches) 
    { 
     userCollection.Add(i); 
    } 
} 

我不是说这是最优雅的解决方案 - 只是简单地想一下为什么你的逻辑失败点。

你也许可以做一些与包含

var results= from i in collection 
      where idList.Contains(i.Id) 
      select i; 

只是不能看到如何把我的头顶部

+0

我不是在数据库的性能非常熟悉,当谈到这样的情况下,但我真的很喜欢它,如果我没有必须为N个字符串执行N个查询。 – 2010-10-04 15:34:52

-3

您可以构造一个表达式树:

var parts = new[] { "Ha", "Ho", "He" }; 

var x = Expression.Parameter(typeof(User), "x"); 

var body = 
    parts.Aggregate<string, Expression>(
     Expression.Constant(false), 
     (e, p) => 
      Expression.Or(e, 
       Expression.Or(
        Expression.Call(
         Expression.Property(x, "LastName"), 
         "StartsWith", 
         null, 
         Expression.Constant(p)), 
        Expression.Call(
         Expression.Property(x, "FirstName"), 
         "StartsWith", 
         null, 
         Expression.Constant(p))))); 

var predicate = Expression.Lambda<Func<User, bool>>(body, x); 

var result = users.Where(predicate); 

结果是相同:

var result = 
    users.Where(x => 
     false || 
     x.LastName.StartsWith("Ha") || x.FirstName.StartsWith("Ha") || 
     x.LastName.StartsWith("Ho") || x.FirstName.StartsWith("Ho") || 
     x.LastName.StartsWith("He") || x.FirstName.StartsWith("He")); 
+0

酷,但你真的**应该**使用'包含'而不是构建表达式。想象一下,有人真的使用这个代码来自动完成。 – 2010-10-04 16:27:30

+0

@gaearon。想象一下!这显然是世界末日。 – dtb 2010-10-04 16:35:31

0

这里是一个班轮(格式化的可读性),我相信返回结果你寻找:

var users = UserRepository.ALL() 
    .ToList() //ToList called only to materialize the list 
    .Where(x => new[] { 'Ha', 'Ho', 'He' } 
     .Any(y => x.LastName.StartsWith(y)) 
    ); //Don't need it here anymore! 

这可能不是你寻求有效的解决方案,但我希望它可以帮助你某种程度上来说!

编辑:正如gaearon指出的,如果'ALL()'命令返回大量记录,我的第一个解决方案可能非常糟糕。试试这个:

var users = UserRepository.ALL() 
     .Where(x => new[] { 'Ha', 'Ho', 'He' } 
      .Any(y => SqlMethods.Like(x.LastName, y + "%")) 
     ); 
+1

我强烈建议使用'任何(...)'而不是'Count(...)> 0'。 – 2010-10-04 16:33:28

+0

是的,我同意!我现在会改变它。 – diceguyd30 2010-10-04 16:45:11

+0

我认为写'Any(...)'比'Where(...)'更好。Any()':-) – 2010-10-04 16:54:09

0

这段代码是为字符串做的。

var users = new [] {"John", "Richard", "Jack", "Roy", "Robert", "Susan" }; 
var prefixes = new [] { "J", "Ro" }; 

var filtered = prefixes.Aggregate(Enumerable.Empty<string>(), 
    (acc, pref) => acc.Union(users.Where(u => u.StartsWith(pref)).ToList())); 

为了您User类它看起来像

var filtered = prefixes.Aggregate(
    Enumerable.Empty<User>(), 
    (acc, pref) => acc.Union(
     users.Where(
      u => u.FistName.StartsWith(pref) || u.LastName.StartsWith(pref) 
      ).ToList())); 
+0

“除了Contains()运算符以外,本地序列不能用于查询运算符的LINQ to SQL实现。” – 2010-10-05 08:26:34

+0

哈哈哈对不起,我在这里非常努力地说:)!@! – Younes 2010-10-05 12:35:33

+0

请考虑编辑后的版本,我不确定它是否可以解决问题。 – 2010-10-05 13:29:55