使用Linq尝试提取具有相应票证的类别列表

问题描述

我正在尝试使用Linq Lambda表达式为特定的userId提取具有相应票证的类别列表。

类别:

public class Category
    {
        public int Id { get; set; }
        public string CategoryName { get; set; }
        public ICollection<Ticket> Tickets { get; set; }
    }

门票:

public class Ticket
    {
        public int Id { get; set; } 
        public string Title { get; set; }

        public User User { get; set; }
        public Category Category { get; set; }
    }

用户

public class User 
    {
        public string Id { get; set; }
        public string UserName { get; set; }
        public ICollection<Ticket> Tickets { get; set; }
    }

这是我到目前为止尝试过的。但这还差得远。

public async Task<IEnumerable<Category>> GetCategories(string userid)
        {
            var categories =  _context.Categories
                                            .Include(c => c.Tickets)
                                            .AsQueryable();
            

            categories = categories
                      .Where(c => c.Tickets.Any(t =>t.User.Id.Equals(id)));            

            return await categories.ToListAsync();
        }
  

如何获得带有特定用户ID的票证的类别列表?

解决方法

问题是这行代码:

categories = categories.Where(c => c.Tickets.Any(t =>t.User.Id.Equals(id)));  

这将返回包含至少1张具有指定用户ID的票证的所有类别,但是将包含该类别中的 all 票证。我的理解是,您只想保留属于指定用户ID的票证。

您的TicketICollection<Ticket>而不是IEnumberable<Ticket>表示的事实使这一点变得更加困难-因为LINQ适用于IEnumerable。这就是进行ToList()调用的原因,该调用导致枚举-在这里要注意一点-Ticket的集合在这一点上不再懒惰。

此代码将执行您想要的操作:

IEnumerable<Category> selection = (from c in categories
                                    select new Category
                                    {
                                        Id = c.Id,CategoryName = c.CategoryName,Tickets = (from t in c.Tickets
                                                    where t.User.Id.Equals(id)
                                                    select t).ToList()
                                    }).Where(c => c.Tickets.Count() > 0);    

但是,我认为,从性能和可读性角度来看,您可能都希望使用循环:

List<Category> selection = new List<Category>();
foreach (var category in categories)
{
    category.Tickets = category.Tickets.Where(t => t.User.Id.Equals(id)).ToList();

    if (category.Tickets.Count > 0)
    {
        selection.Add(category);
    }
}

最后,由于您的Ticket类仍然携带Category信息,因此可能值得使用SelectMany来简化列表:

var selection = categories.SelectMany(c => c.Tickets.Where(t => t.User.Id.Equals(id)));

这将返回Ticket s的扁平化列表-但仅返回与所有类别中的指定用户ID匹配的列表。这样做的优点是保持懒惰(仍然是IEnumerable),比较简单,并且很可能比其他选项具有更高的性能;但是,您不再有嵌套列表。

请选择!

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...