使用LINQ会更好吗?

时间:2011-11-10 16:07:05

标签: c# performance linq datatable

下面的方法选择管理员权限并从缓存的DataTable返回bool,它是否会更好地使用Linq?

你可能会问为什么不测试它。好吧,由于缺乏知识,我无法在Linq中编写

 DataRow[] result = PrivilegeMap.Select("privilegeActionId=" + (int)actionId);
            bool moderatorHasIt = Convert.ToBoolean(result[0]["moderatorHasIt"]);
            bool adminHasIt = Convert.ToBoolean(result[0]["adminHasIt"]);                                        
            if (myRole == User.Role.Admin)
            {
                return Convert.ToBoolean(adminHasIt);
            }
            if (myRole == User.Role.Moderator)
            {
                return Convert.ToBoolean(moderatorHasIt);
            }
            else
            {
                return false;
            }

3 个答案:

答案 0 :(得分:2)

可以

我们假设以下内容:

  1. 基础表的起始大小,读取频率和更新频率的平衡使得将整个内容全部加载到内存中并且只是反复查看它就没有意义。

  2. 每个ID只有一个匹配的行。

  3. 这一排还有很多其他有趣的字段,我们在这里并不关心。

  4. 然后,如果我们用Linq2SQL Table<Privileges>替换PrivilegeMap,则等效的LINQ代码将类似于:

    var result = PrivilegeMap.Where(p => p.PrivilegeActionId == actionID).Select(p => new{p.ModeratorHasIt, p.AdminHasIt}).First()
    if (myRole == User.Role.Admin)
    {
      return result.AdminHasIt;
    }
    if (myRole == User.Role.Moderator)
    {
      return result.ModeratorHasIt;
    }
    else
    {
      return false;
    }
    

    (就此而言var result = PrivilegeMap.Where(p => p.PrivilegeActionId == actionID).First(p => new{p.ModeratorHasIt, p.AdminHasIt})也可以写成var result = (from p in PrivilegeMap where p.PrivilegeActionId == actionID select new{p.ModeratorHasIt, p.AdminHasIt}).First()这只是针对相同LINQ操作的不同语法。)

    让我们说actionID2 您的代码将按以下方式转换为SQL:

    SELECT * FROM Privileges WHERE privilegeActionId = 2

    上面的Linq将变成:

    SELECT TOP 1 adminHasIt,moderatorHasIt FROM Privileges WHERE privilegeActionId

    你可以看到,如果这是一个包含大量列的表和/或如果有多个匹配的行,这可能会更有效。

    (如果PrivilegeMap是可枚举但不可查询的,那么它将变成一个整个事物被加载和扫描的操作,因此根本没有效率。)

    另一方面,生成该SQL的代码可能更复杂,并且在设置权限实体对象时需要一些工作。如果这是一次性操作,就开发人员或运行时效率来说肯定是不值得的,但除此之外它可能会使两者都受益。

    然而,请注意,在我们的两个案例中,我们都在不必要地进行查询。我实际上用以下代替我:

    if (myRole == User.Role.Admin)
    {
      return PrivilegeMap.Where(p => p.PrivilegeActionId == actionID).Select(p => p.AdminHasIt).First();
    }
    if (myRole == User.Role.Moderator)
    {
      return PrivilegeMap.Where(p => p.PrivilegeActionId == actionID).Select(p => p.ModeratorHasIt);
    }
    else
    {
      return false;
    }
    

    要么只查询adminHasIt,只查询moderatorHasIt,要么根本不查询,因为无论数据库状态如何,我们都会保证myRole的任何其他值为false。< / p>

    同样,您可以通过以下方式获得更简单的改进:

    if(myRole != User.Role.Admin && myRole != User.Role.Moderator)
      return false;
    DataRow[] result = PrivilegeMap.Select("privilegeActionId=" + (int)actionId);
    if (myRole == User.Role.Admin)
    {
      return Convert.ToBoolean(result[0]["adminHasIt"]);
    }
    if (myRole == User.Role.Moderator)
    {
      return Convert.ToBoolean(result[0]["moderatorHasIt"]);
    }
    

    这里我们首先完全避免数据库查询,如果我们不能使用它,只转换我们关心的字段,并且不随后将bool转换为bool。这种对实际使用的数据的本地思考要容易得多,而且大多数这样的节省很少,有些很大(这可能是这样),而且这是习惯问题,而不是复杂的权衡。 / p>

答案 1 :(得分:1)

您列出的代码不完整,因为未定义myRole变量。

考虑到这一点,我建议在switch语句中编写它并继续进行直到它被识别为问题。此外,它更容易阅读(在我看来)。

答案 2 :(得分:1)

使用LINQ可能会更快,因为数据表不必解析您的查询字符串,但是您可以通过更改数据表示来获得最大的优势,以避免首先查询数据表。

创建一个代表您感兴趣的权限的IDictionary<int, bool>,由actionId键入。然后,当您需要进行查找时,您只需返回dict[actionId

无论如何,我怀疑这可能是过早优化的情况:您是否测试过您的程序并发现这段代码占据了处理时间的很大一部分?