[asp.net]合并 2 C# IQueryable

标签: Asp.net Linq C#
发布时间: 2017/3/26 5:33:19
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

我没有很多的经验与 IQueryable

我想做是搜索用户基于传入的约束,可以是用户名或电话号码的列表。根据类型我想要返回有限的信息。然后,我想要将 3 IQueryables 合并成一个和结合条目匹配 id 和用户名,以保持最多的信息。

这里是我到目前为止有︰

public IQueryable<User> Search(String[] criteria)
{
        var query = Database.Get<User>();

        IQueryable<User> phoneQuery = null;
        IQueryable<User> emailQuery = null;
        IQueryable<User> nameQuery = null;

        foreach (String str in criteria)
        {
            // Check if it is a phone number
            if (Regex.IsMatch(str, @"([0-9]{3})?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$"))
            {
                phoneQuery = query.Where(
                       u => u.PhoneNumber.ToLower() == (str))
                       .Select(i => new User
                       {
                           Id = i.Id,
                           UserName = i.Name,
                           PhoneNumber = i.PhoneNumber
                       })
            }
            // check if it is an email 
            else if (criteria.Contains("@"))
            {
                emailQuery = query.Where(
                       u => u.Email.ToLower() == (str))
                       .Select(i => new User
                       {
                           Id = i.Id,
                           UserName = i.Name,
                           Email = i.Email
                       })
            }
            else
            {
                nameQuery = query.Where(
                       u => u.UserName.ToLower() == (str))
                       .Select(i => new User
                       {
                           Id = i.Id,
                           UserName = i.Name,
                       })
            }
        }
        // Merge the 3 queries combining entries if the username and id match and maintain the maximum amount of information

        return query;

    }

解决方法 1:

有几个问题与您的代码︰

ToList()将执行查询。如果你调用 AsQueryable() 以后,你只是在局部对象上创建对象查询。这基本上失去的概念 IQueryable ,所以你会更好地删除所有 ToList()AsQueryable() 的调用。

你可以使它单个查询而不是合并三个查询,如下所示︰

Expression predicateBody = Expression.Constant(false);
Expression userParameter = Expression.Parameter("user", typeof(User));
Expression userUserName = Expression.MakeMemberAccess(...);
Expression userPhoneNumber = Expression.Cal(...);
Expression userEmail = Expression.Call(...);

foreach (String str in criteria)
{
    // Check if it is a phone number
    if (Regex.IsMatch(str, @"([0-9]{3})?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$"))
    {
         predicateBody = Expression.Or(predicateBody, Expression.Equals(userPhoneNumber, Expression.Constant(str)));
    }
    // check if it is an email 
    else if (criteria.Contains("@"))
    {
         predicateBody = Expression.Or(predicateBody, Expression.Equals(userEmail, Expression.Constant(str)));
    }
    else
    {
         predicateBody = Expression.Or(predicateBody, Expression.Equals(userUserName, Expression.Constant(str)));
    }
}

return query.Where(Expression.Lambda<Func<User, bool>>(predicateBody, userParameter))
     .GroupBy(u => u.Id)
     .Select(users => new User()
          {
               Id = users.Key,
               UserName = users.Select(u => u.UserName).Intersect(criteria).FirstOrDefault(),
               Email = users.Select(u => u.Email).Intersect(criteria).FirstOrDefault(),
               PhoneNumber = users.Select(u => u.PhoneNumber).Intersect(criteria).FirstOrDefault()
          });

编辑对不起,我误解了合并的问题。

Edit2如果预先排序标准,也是一种解决方案,不需要手动创建表达式目录树。

Edit3我忘了的有限信息部分参见

var phoneNumbers = new List<string>();
var emails = new List<string>();
var userNames = new List<string>();

foreach (var str in criteria)
{
    // Check if it is a phone number
    if (Regex.IsMatch(str, @"([0-9]{3})?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$"))
    {
         phoneNumbers.Add(criteria);
    }
    // check if it is an email 
    else if (criteria.Contains("@"))
    {
         emails.Add(crietria);
    }
    else
    {
         userNames.Add(criteria);
    }
}

return query.Where(u => phoneNumbers.Contains(u.PhoneNumber)
       || emails.Contains(u.Email)
       || userNames.Contains(u.UserName))
       .GroupBy(u => u.Id)
       .Select(users => new User()
              {
                   Id = users.Key,
                   UserName = users.Select(u => u.UserName).Intersect(userNames).FirstOrDefault(),
                   Email = users.Select(u => u.Email).Intersect(emails).FirstOrDefault(),
                   PhoneNumber = users.Select(u => u.PhoneNumber).Intersect(phoneNumbers).FirstOrDefault()
              });
官方微信
官方QQ群
31647020