【问题标题】:Simple LINQ to SQL extension method简单的 LINQ to SQL 扩展方法
【发布时间】:2011-01-18 00:59:23
【问题描述】:

我将如何编写一个名为“IsActive”的简单 LINQ to SQL 扩展方法,该方法将包含对几个不同字段的一些基本条件检查,以便我可以在所有地方重用这个“IsActive”逻辑而不复制逻辑.

例如,我希望能够做这样的事情:

return db.Listings.Where(x => x.IsActive())

IsActive 类似于:

public bool IsActive(Listing SomeListing)
{
    if(SomeListing.Approved==true && SomeListing.Deleted==false)
        return true;
    else
        return false;
}

否则,我将不得不在整个系统中的一百万个不同查询中复制相同的旧 where 条件。

注意:方法必须在 SQL 中呈现..

【问题讨论】:

    标签: linq-to-sql extension-methods criteria


    【解决方案1】:

    好问题,显然需要能够定义一个可重用过滤表达式,以避免在不同的查询中重复指定逻辑。

    此方法将生成一个过滤器,您可以将其传递给 Where 方法。

    public Expression<Func<Listing, bool>> GetActiveFilter()
    {
      return someListing => someListing.Approved && !someListing.Deleted;
    }
    

    然后,通过以下方式调用它:

    Expression<Func<Filter, bool>> filter = GetActiveFilter()
    return db.Listings.Where(filter);
    

    由于使用了Expression&lt;Func&lt;T, bool&gt;&gt;,所以翻译成sql没有问题。


    这是一种额外的方法:

    public static IQueryable<Filter> FilterToActive(this IQueryable<Filter> source)
    {
      var filter = GetActiveFilter()
      return source.Where(filter);
    }
    

    然后,

    return db.Listings.FilterToActive();
    

    【讨论】:

    • 有趣。我不知道 Expression&lt;TDelegate&gt; 类。
    【解决方案2】:

    您可以使用部分类来实现这一点。

    在新文件中放置以下内容:

    namespace Namespace.Of.Your.Linq.Classes 
    {
        public partial class Listing 
        {
            public bool IsActive()
            {
                if(this.Approved==true && this.Deleted==false)
                    return true;
                else
                    return false;
            }
        }
    }
    

    由于列表对象(您的 lambda 中的 x)只是一个对象,并且 Linq to SQL 将生成的类定义为部分类,因此您可以使用部分类向生成的类添加功能(属性、方法等)。

    我不相信上述内容会呈现到 SQL 查询中。如果您想在 SQL 查询中执行所有逻辑,我建议您创建一个调用 where 方法的方法,并在必要时调用它。

    编辑

    例子:

    public static class DataManager
    {
        public static IEnumerable<Listing> GetActiveListings()
        {
            using (MyLinqToSqlDataContext ctx = new MyLinqToSqlDataContext())
            {
                return ctx.Listings.Where(x => x.Approved && !x.Deleted);
            }
        }
    }
    

    现在,只要您想获得所有活跃列表,只需致电DataManager.GetActiveListings()

    【讨论】:

    • 酷。谢谢。这可以转化为 SQL 吗?
    • Kyle,我上面的示例是直接查询数据库,即返回 db.Where(我没有 ToList()),因此它可以转换为 SQL 很重要,因为我不会正在使用本地对象。您能否概述如何实现您的第二个建议,即制作调用 Where 方法的方法?再次感谢。
    • 在我的答案中添加了一个示例。基本上,创建一个返回您正在寻找的活动列表的方法。
    • 太好了,谢谢凯尔。我按照这些思路做了一些事情,它确实很好用。我读到 LINQ to SQL 试图在运行时将所有内容优化为单个 SQL 查询,因此即使您通过许多此类“标准过滤器”方法运行结果,最终结果应该是好的。 触摸木头
    • 我发现了一件困难的事情:如果Linq扩展方法返回IEnumerable&lt;T&gt;,那么它不会被翻译成SQL。如果 Linq 扩展方法返回 IQueryable&lt;T&gt;,它将是。请记住这一点,您可能希望在我的示例中更改方法的返回类型以反映这一点。当IQueryable&lt;T&gt; 转换为IEnumerable&lt;T&gt; 或单个对象(通过.ToArray().Single().Cast() 等)时,Linq to SQL 运行时对数据库运行查询
    【解决方案3】:
    public static class ExtensionMethods
    {
      public static bool IsActive( this Listing SomeListing)
      {
        if(SomeListing.Approved==true && SomeListing.Deleted==false)
            return true;
        else
            return false;
      }
    }
    

    【讨论】:

    • 谢谢,看起来很干净。这可以转化为 SQL 吗?
    • 局部类在这种情况下会更合适。
    【解决方案4】:

    在这里聚会迟到了,但我使用的另一种方法是:

    public static IQueryable<Listing> GetActiveListings(IQueryable<Listing> listings)
    {
        return listings.Where(x => x.Approved && !x.Deleted);
    }
    

    然后

    var activeListings = GetActiveListings(ctx.Listings);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多