【问题标题】:How do I filter out child collection in EF6.1如何在 EF6.1 中过滤掉子集合
【发布时间】:2018-03-06 23:56:31
【问题描述】:

我有一个应用程序、AppRoles、UserAppRoles 和用户。我正在尝试获取所有用户,但只想要 AppId = 1 的 AppRoles。如何过滤子集合?

using (var context = new dbContext())
            {
                var rv = context.Users
                       .Include(u => u.AppRoles);                           

            }

我试过这个但是抛出异常: 包含路径表达式必须引用在类型上定义的导航属性。对引用导航属性使用虚线路径,对集合导航属性使用 Select 运算符

public static async Task<List<User>> GetAllAsync()
        {
            var rv = new List<User>();

            using (var context = new dbContext())
            {
                rv = await (context.Users.AsNoTracking()
                    .Include(a => a.AppRoles.Where(a2 => a2.AppId == 1)).ToListAsync());
            }

           return rv;

        }

我能弄清楚如何让它工作的唯一方法就是这样,我还不如在这一点上使用存储过程:

var rv = new List<User>();

            using (var context = new dbContext())
            {
               rv = context.Users.AsNoTracking()
                    .Include(a => a.AppRoles).ToList();


            }

            foreach (var user in rv)
            {
                if (user.AppRoles.Any())
                {
                    user.AppRoles = user.AppRoles.Where(r2 => r2.AppId == 1).ToList();
                }
            }

如何在 EF 中编写这个?

SELECT        
Users.UserId, 
Users.UserName
FROM          
Users 

INNER JOIN UserAppRoles ON Users.UserId = UserAppRoles.UserId 
INNER JOIN AppRoles ON UserAppRoles.AppRoleId = AppRoles.AppRoleId
WHERE AppRoles.AppId = 1

【问题讨论】:

  • 可能是Linq join
  • 您能否提供使用上述代码的 sn-p 代码,我仍然无法使其正常工作。谢谢
  • 你们的关系是如何建立的?如果您可以在 SQL 中编写连接,那么 Linq 查询将非常相似。 lambda 风格只是受虐狂。
  • 我有 Apps、AppRoles、UserAppRoles 和 Users 表,UserAppRoles 加入了 AppRoles 和 Users 表(UserId 和 AppRoleId 都是 pk),AppsRoles 是 Apps 的子级,1:m 到 UserAppRoles。
  • 上面的sql我加了

标签: entity-framework entity-framework-6


【解决方案1】:

试试这个:

context.Entry(user) 
        .Collection(b => b.AppRoles) 
        .Query() 
        .Where(r => r.AppId==1) 
        .Load(); 

其中user 是上下文中的 AppUser 实体(如您的 foreach 示例中)。

更多信息在这里:

https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx(“显式加载相关实体时应用过滤器”部分)

【讨论】:

    【解决方案2】:

    您可以对 AppRoles 进行子查询

    var arQuery = from ar in context.AppRoles
                  where ar.AppId == 1
                  select ar;
    
    var query = from u in context.Users
                join uar in context.UserAppRoles on u.UserId equals uar.UserId
                join ar in arQuery on uar.AppRoleId equals ar.AppRoleId
                select u;
    

    【讨论】:

    • 没有 UserAppRoles 对象,UserAppRoles 只是用户和 AppRoles 对象上的导航属性。用 EF 做内部连接真的有那么复杂吗?使用存储过程和 ado.net 而不使用 EF 可能会更好,难怪它没有良好的声誉......如果不使用 EF,我会长期这样做。这也会查询数据库两次,这对我来说没有任何意义,而且似乎效率低下。
    • 生成一个 SQL 查询。您可以记录请求或观看分析器。
    【解决方案3】:

    我有这样的工作,但似乎仍然效率低下,但猜测它比往返数据库更好。这不是常见的模式吗?我不敢相信 EF 中不包含简单的内部联接,但无论如何我都在映射到 DTO,所以猜想这现在可以工作,直到我研究一些支持过滤的开源 Include 过滤器。

    var rv = context.Users.Include(r => r.AppRoles).ToList().Select(u => new User()
                    {
                        UserId = u.UserId,
                        AppRoles = u.AppRoles.Where(x=>x.AppId == 1).ToList()
    
    
                    });
    

    【讨论】:

      【解决方案4】:

      免责声明:我是项目的所有者Entity Framework Plus

      EF+ Query IncludeFilter 允许轻松过滤包含的实体。

      public static async Task<List<User>> GetAllAsync()
      {
          var rv = new List<User>();
      
          using (var context = new dbContext())
          {
              rv = await (context.Users.AsNoTracking()
                  .IncludeFilter(a => a.AppRoles.Where(a2 => a2.AppId == 1)).ToListAsync());
          }
      
         return rv;
      }
      

      维基:EF+ Query Include Filter

      【讨论】:

      • 太棒了,我去看看,这正是我要找的!
      • 它仍然不适合我,角色是空的。我正在通过 web api 使用,所以不确定这是一个问题,无论如何这需要很长时间,所以求助于存储过程和异步 ado.net,效果要好得多。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-01
      • 2020-11-24
      • 2021-01-15
      • 2017-04-12
      • 1970-01-01
      • 2021-12-11
      • 1970-01-01
      相关资源
      最近更新 更多