带有if的复杂查询

本文关键字:查询 复杂 if 带有 | 更新日期: 2023-09-27 18:00:16

我需要做一个类似getUsers(列表ID)的查询;我需要按ID进行搜索,如果找到了,则返回列表中有ID的用户,如果没有找到,则返回所有用户,或者如果只找到一个,则返回一个用户。

如何编写此查询?

我就是这样开始的:

 public List<User> getUsers (List<int> ids)        
 {
    using(var uow = _repository.CreateUnitOfWork())
    {               
        var u = uow.GetEntities<User>().Where(c => c.Id in ids);
        if (u == null) 
        u.ToList();                     
    }
}

带有if的复杂查询

您的问题没有意义,因为函数的返回类型必须始终相同。它不能在某些时间返回List,在其余时间返回User

我建议这样做:

public IEnumerable<User> GetUsersByIdOrAllUsers(IEnumerable<int> ids)
{
    using (var uow = _repository.CreateUnitOfWork())
    {
        var users = uow.GetEntities<User>();
        if (users.Any(c => ids.Contains(c.ID)))
        {
            return users.Where(c => ids.Contains(c.ID));
        }
        return users;
    }
}

然后你可以测试你是否只找到一个用户:

var matchingUsers = GetUsersByIdOrAllUsers(ids);
if (matchingUsers.Any() && !matchingUsers.Skip(1).Any())
{
    var singleUser = matchingUsers.Single();
    // Do stuff with the single user...
}

请注意,IEnumerable的使用会使操作变得懒惰,从而提高效率。如果您真的想要List,只需执行:

var matchingUsersList = matchingUsers.ToList()

假设uow.GetEntities<User>()返回IQueryable<User>,当列表中有ID的用户时,所提出的解决方案包括执行两个昂贵的IN (...) SQL查询,还构建两次ids列表并将其传递到数据库,一次用于Any,一次为Where

我宁愿用不同的方式来构建它。我会在ids.Contains的基础上用Where执行一个查询,并将结果具体化到内存中。然后,我会在本地检查它是否包含数据,如果是,将返回结果,其他人将执行第二个查询,而不使用过滤器,这应该会更有效率。

类似这样的东西:

public List<User> getUsers (List<int> ids)        
{
    using(var uow = _repository.CreateUnitOfWork())
    {               
        var allUsers = uow.GetEntities<User>();
        var matchingUsers = allUsers
            .Where(user => ids.Contains(user.Id))
            .ToList();
        return matchingUsers.Any() ? matchingUsers : allUsers.ToList();
    }
}

概括一下,您不能用一个数据库查询来执行您想要的操作。它至少需要执行两个查询,唯一的问题是使用最有效的方法。

一个简单的方法是使用Join

public List<User> getUsers (List<int> ids)        
 {
    using(var uow = _repository.CreateUnitOfWork())
    {               
        var u = uow.GetEntities<User>()
                      .Join(ids,x=>x.Id,y=>y,(x,y)=>x).ToList();
        if (u.Count==0) 
               return uow.GetEntities<User>().ToList()
         return u;           
    }
}

不确定是否有一种不那么健谈的方法可以做到这一点,但从逻辑上讲,可能是这样的?:

if (uow.GetEntities<User>().Any(u => ids.Contains(u.ID))
    return uow.GetEntities<User>().Where(u => ids.Contains(u.ID)).ToList();
return uow.GetEntities<User>().ToList();

我在这里假设uow.GetEntities<User>()只是返回一个可查询的,它本身不会从数据库中实现任何内容,也不会有任何显著的性能损失。如果不是这样,则可能需要将此操作的代码放在DAL中更深的位置。

public IList<User> getUsers (List<int > ids = null)
{                       
        var query = _repository.GetEntities<User>();
        if (ids == null)                
            return query.ToList();                  
        if (ids.Count()==1)
        {                    
             var singleUser = query.FirstOrDefault(user => ids.Contains(user.Id));
             if (singleUser!= null)                                     
                return new List<User>{ singleUser; };           
             return new List<User>();                
        }   
        return query.Where(user => ids.Contains(user.Id)).ToList();                                                     
}