简单的 LINQ to SQL 扩展方法

3

我该如何编写一个简单的LINQ to SQL扩展方法,名为“IsActive”,其中包含几个基本的条件检查和一些不同字段的查询,以便在不重复逻辑的情况下可以在许多地方重用此“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中呈现。
4个回答

5

好问题,有一个明显的需求需要定义一个可重复使用的过滤表达式,以避免在不同的查询中冗余指定逻辑。

这种方法将生成一个过滤器,您可以将其传递给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<Func<T, bool>>,因此将其转换为SQL时不会出现问题。


以下是另一种实现方式:

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

稍后,
return db.Listings.FilterToActive();

有趣。我不知道 Expression<TDelegate> 类。 - Kyle Trauberman

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

谢谢,看起来很干净。这个能够顺利转换成SQL吗? - Aaron
在这种情况下,局部类更为合适。 - Kyle Trauberman

0
你可以使用局部类来实现这个目标。
在一个新文件中放置以下内容:
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将生成的类定义为partial,因此您可以使用partial类向生成的类添加功能(属性、方法等)。

我不认为上述内容会被渲染到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吗? - Aaron
Kyle,我上面的示例是直接查询数据库,即返回db.Where(我没有使用ToList()),因此重要的是它可以转换为SQL,因为我不会使用本地对象。您能概述一下如何实现您的第二个建议,即调用Where方法的方法吗?再次感谢。 - Aaron
在我的回答中添加了一个示例。基本上,创建一个返回您要查找的活动列表的方法。 - Kyle Trauberman
太好了,谢谢Kyle。我选择了类似的东西,它确实很好用。我读到LINQ to SQL会尝试在运行时将所有内容优化为单个SQL查询,因此即使您通过许多这些“条件过滤器”方法运行结果,最终的性能也应该还不错... 碰碰木头 - Aaron
1
我从艰难的经验中发现了一些事情:如果Linq扩展方法返回IEnumerable<T>,那么它不会被转换为SQL。如果Linq扩展方法返回IQueryable<T>,则会被转换为SQL。记住这一点,您可能需要更改我的示例中方法的返回类型以反映这一点。当将IQueryable<T>转换为IEnumerable<T>或单个对象(通过.ToArray().Single().Cast()等)时,Linq to SQL运行时会针对数据库运行查询。 - Kyle Trauberman

0
有点晚了,但我用的另一种方法是:
public static IQueryable<Listing> GetActiveListings(IQueryable<Listing> listings)
{
    return listings.Where(x => x.Approved && !x.Deleted);
}

然后

var activeListings = GetActiveListings(ctx.Listings);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接