使用Where子句的高效EF查询

时间:2019-07-30 22:24:21

标签: c# entity-framework-6

我们要根据传递给该方法的值列表来过滤出“视图”行。

public List<Model.View_RegOrgUserInfo> GetAdminInfoList(List<string> adminWwids)
        {
            try
            {
                using (var ctx = new Context())
                {
                  return ctx.View_RegOrgUserInfo.Where(x => adminWwids.Contains(x.WWID.Value.ToString())).ToList();
                }
            }
            catch (Exception ex)
            {
                onboardingLogger.LogException(ex); throw ex;
            }
        }

adminWWIDs是字符串列表,而View中的WWID列是int?,但是我们在这里看到了超时异常。 adminWWIDs列表包含约1万个项目,视图包含约20万行 我不确定我们在做错什么以及如何提高效率。

例外:

"Message":"An error has occurred.","ExceptionMessage":"The wait operation timed out","ExceptionType":"System.ComponentModel.Win32Exception"

2 个答案:

答案 0 :(得分:0)

根据对数据库的访问,10,000个列表的更改频率以及调用频率,您可以将10,000个项目加载到数据库的临时表中,然后使用EF连接获取您想要的数据。

当然,您可以遍历200,000行,并使用LINQ作为对象来比较和查找数据,但是除非它是一个很小的表和一个本地数据库,否则可能不会很有效。

答案 1 :(得分:0)

对于操作超时异常,是因为默认情况下EF具有15或30秒的超时时间。

对您的代码进行IP改进:

1-添加以下代码,以便您的查询完成并且不会引发异常

ctx.Database.CommandTimeout = 3000;

2-使用异步始终是最佳实践

3-使用AsNoTracking()

await ctx.View_RegOrgUserInfo.Where(x => adminWwids.Contains(x.WWID.Value.ToString())).AsNoTracking().ToListAsync();

4-您可以尝试在函数内部将列表转换为列表,然后

await ctx.View_RegOrgUserInfo.Where(
x => x.WWID != null &&
adminWwids.Contains(x.WWID)
).AsNoTracking().ToListAsync();

如果上述方法仍然不能满足您的要求,则可以尝试执行以下操作:

    var parameters = string.Join("," , adminWwids); 
    var query = $"SELECT * FROM VIEW_REGORUSERINFO WHERE WWID IN (parameters);

    return await db.Database.SqlQuery<VIEW_REGORUSERINFO>(query).AsQueryable().AsNoTracking().ToListAsync();