1

具有大量 AND/OR 组件的复杂语句难以阅读并且容易出错 - 在普通的 IF 语句中,我可能会使用方法调用来简化 is 语句 - 例如:

        if (((user == myUser || user == yourUser) && user != Admin)
            && Something > SomethingElse
            && (thresholdDate > item.itemDate || (item.itemDate == null && item.itemType == itemIsDated))
            )
        {
            DoStuff();
        }

我可以重构用户和日期部分以使事情更容易阅读:

        if (
            UserValid(user)
            && Something > SomethingElse
            && DateIsValid(thresholdDate, item)
           )
        {
            DoStuff();
        }

我可以在 LINQ 查询中做什么来简化嵌套的 IF?

例如,如果我有以下内容:

        var someResults = DataManager.Things
                                        .Where(item => (item.UserName == currentUser.UserName
                                                        || item.ParentUsername == currentUser.UserName)
                                                       && (item.ItemType == (int) ItemType.MyType
                                                           || item.ItemType == (int) ItemType.YourType)
                                                       && item.Result == null
                                                       && (
                                                              (item.Status == null
                                                               && (item.ItemDate < thresholdDate
                                                                   || item.ItemType == (int) ItemType.YourType)
                                                              )
                                                              ||
                                                              (item.Status != null &&
                                                               item.Status != "Rejected")
                                                          )
            )

** 不是实际代码 - 只是一个简化和通用的示例。

我希望能够将部分逻辑提取到方法中 - 或者以其他方式分离出 AND / OR 混乱,以便清楚发生了什么。

我尝试向“项目”添加一个方法来执行某些逻辑一种 IsValidType(typeOptions) 方法 - 这编译得很好,但 LINQ 抱怨它在运行时无法识别该方法。

我可以在项目上使用一个属性 - 但是我不能传递任何上下文信息(这使得它的使用受到限制)

你如何使这种查询可读?

4

3 回答 3

0

正如 Tim 在评论中提到的,您可以在大多数 LINQ-to-something 实现中使用方法。结果将如下所示:

.Where(item => CheckUserName(item)
    && CheckItemType(item)
    && CheckItemResult(item)
    && CheckItemStatus(item));

对于 LINQ to SQL、LINQ to Entities 或其他远程执行的实现,您至少可以利用查询优化并将所有内容重写&&为单独的Where调用,因为它们是等效的:

.Where(item => item.UserName == currentUser.UserName
    || item.ParentUsername == currentUser.UserName)
.Where(item => item.ItemType == (int) ItemType.MyType
    || item.ItemType == (int) ItemType.YourType)
.Where(item => item.Result == null)
.Where(item => (item.Status == null
    && (item.ItemDate < thresholdDate
        || item.ItemType == (int) ItemType.YourType))
    || (item.Status != null
        && item.Status != "Rejected"));

生成的查询会将 where 子句连接到一个枚举器中。

于 2012-11-21T13:07:10.987 回答
0

我假设您不能直接在代码中执行此操作。当然,如果你有很多类似的条件,你可以动态地为它们生成表达式。但是你可以用一个大的 Where 条件做很少的事情而不影响性能 =(.

如果您认为它更合适,您可以将您的单个大条件拆分为几个随后的 Where() 调用。转换为 SQL 时的 LINQ 树会合并条件并生成单选。DBMS 还可以优化生成的 SQL 以获得最大效率。因此,在某些情况下,您可以故意编写未优化的查询以获得更好的可读性并依赖自动优化。尽管要小心并检查您的特定条件是否真的如您所愿地合并和优化。

如果您可以将此代码移动到 SQL 存储过程,则可以配置 LINQ to SQL 以在需要时调用此过程。这将简化调用代码,但将复杂性转移到 SQL。我想您甚至可以将一些条件提取到 SQL 函数中,并在 Where 子句中使用它们来调用它们。虽然老实说我从未使用过它 - 只是阅读了可能性。有关更多详细信息和示例,请查看本文:http ://weblogs.asp.net/zeeshanhirani/archive/2008/05/21/table-valued-functions-in-linq-to-sql.aspx

于 2012-11-21T13:17:59.787 回答
0

三个非常不同的选择:

  • 使用锐器。它包含许多代码检查和重构,以减少 if 语句或指出冗余谓词。
  • 在 linq-to-sql 中,您可以跳过对null. 那是因为表达式被翻译成 SQL 并且在 SQL 中没有空引用异常。where a.Name == "x"false没有a. _ 在 linq-to-objects 中,这将引发空引用异常。
  • 对于经常进行的比较,可以考虑将计算列添加到数据库表中。就像一个IsRejected评估的列Status = 'Rejected'。在 linq 中,这将减少到where !item.IsRejected.
于 2012-11-21T14:18:32.853 回答