【问题标题】:How to refactor multiple similar Linq queries?如何重构多个相似的 Linq 查询?
【发布时间】:2010-10-26 04:16:10
【问题描述】:

假设我有以下两个想要重构的 Linq 查询:

var someValue1 = 0;
var someValue2= 0;
var query1 = db.TableAs.Where( a => a.TableBs.Count() > someValue1 )
                  .Take( 10 );
var query2 = db.TableAs.Where( a => a.TableBs.First().item1 == someValue2)
                  .Take( 10 );

请注意,只有 Where 参数会发生变化。有什么方法可以将查询放在方法中并将 Where 参数作为参数传递?

【问题讨论】:

    标签: c# .net linq linq-to-sql refactoring


    【解决方案1】:

    您可以使用Predicate<T>

    public IQueryable<TableA> Helper(Predicate<TableA> predicate)
    {
        return db.TableAs.Where(predicate).Take(10);
    }
    

    就这样称呼吧。

    var query1 = Helper(a => a.TableBs.Count() > someValue1);
    var query2 = Helper(a => a.TableBs.First().item1 == someValue2);
    

    并且给一个比Helper更好的名字。

    【讨论】:

    • 有点离题,但该方法不应该是私有的或静态的或两者兼而有之吗?
    • 视情况而定 - 它可能是辅助类的公共方法或使用它的类的私有方法。它可能是静态的,但为了更好的可测试性,也可能决定让它保持非静态。我不会尝试根据这几行代码猜测最好的方法。
    • 只是一个更正,Where 接受 Func 而不是 Predicate,但我明白了。
    【解决方案2】:

    您可以像重构任何其他代码一样做到这一点:

    T MyQuery(U db, Func<TSource, bool> pred) {
      return db.TableAs.Where( pred )
                      .Take( 10 );
    }
    

    其中 T 和 U 是与您的查询相关的任何类型。

    【讨论】:

    • 我不习惯 lambda 表达式,所以我没有意识到它是如此明显。
    • lambda 表达式只不过是 Func 委托的语法糖,其中插入了适当的泛型类型。没有魔法。 :)
    • 此解决方案不起作用:不支持的重载用于查询运算符“Where”。
    • 那么您很可能使用了错误的类型。谓词的第一个通用参数必须是它工作的可枚举/可查询的元素类型。如果没有看到更多代码(或者至少我们正在使用哪些类型),很难准确地说出问题出在哪里
    • 啊,是的,这很可能是问题所在。 LinqToSql 比较挑剔,因为它必须能够将谓词函数编译成 SQL。
    【解决方案3】:

    当然有。 where 参数只是 Func&lt;T, bool&gt; 类型的简单闭包(其中 T 是您的 DB 项的类型 - 我不知道它们在您的代码中),您可以将其包装到(匿名)函数中。

    Func<Func<T, bool>, IEnumerable<T>> MakeQuery = (Func<T, bool> whereParam) => db.TableAs.Where(whereParam).Take(10);
    

    这样使用

    var query1 = MakeQuery(a => a.TableBS.Count() > someValue1);
    

    【讨论】:

    • 为什么要在rhs上指定type参数?它从 lhs 中推断出来,使代码更短、更易读。
    【解决方案4】:

    是的,参数类型是lamba表达式Func&lt;TSource, bool&gt;

    Func<Person, bool> c1 = p => p.LastName == "1";
    Persons.Where(c1);
    Func<Person, bool> c2 = p => p.FirstName == "2";
    Persons.Where(c2)
    

    【讨论】:

    • 这不起作用:不支持用于查询运算符“Where”的重载。
    • 是的,我在这里发布之前编译并运行过。
    • 好吧,我知道为什么。我没有意识到这是针对 Linq to Sql 的。
    • 如果您知道原因,请在新问题中发布答案:stackoverflow.com/questions/865350/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 1970-01-01
    • 1970-01-01
    • 2015-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多