C# 在LINQtoSQL中,如何将LINQ查询的一部分传递给函数

C# 在LINQtoSQL中,如何将LINQ查询的一部分传递给函数,c#,linq,linq-to-sql,expression-trees,C#,Linq,Linq To Sql,Expression Trees,是否可以将linq查询的一部分传递到函数中? 我想为我的DAL创建一个始终使用相同查询接口的公共接口。比如说, List<T> Get(Join j, Where w, Select s){ return currentDataContext<T>.Join(j).Where(w).Select(s).ToList(); } 这可能吗?我想这可以通过表达式树来完成,但我还没有找到它的示例。您可以使用参数并将其作为字符串传递。检查此泛型类: 它基本

是否可以将linq查询的一部分传递到函数中? 我想为我的DAL创建一个始终使用相同查询接口的公共接口。比如说,

List<T> Get(Join j, Where w, Select s){    
    return currentDataContext<T>.Join(j).Where(w).Select(s).ToList();    
}
这可能吗?我想这可以通过表达式树来完成,但我还没有找到它的示例。

您可以使用参数并将其作为字符串传递。

检查此泛型类:

它基本上使用Func委托应用Where谓词:

//...
public TableView(DataContext dataContext, Expression<Func<TEntity, bool>> predicate)
{
    this.table = dataContext.GetTable<TEntity>();
    this.baseQuery = table.Where(predicate);
    this.predicate = predicate.Compile();
}
//...

嗯,连接是很棘手的,因为很难表达连接-但是像where/select/orderby这样的事情非常简单

实际上,这只是在IQueryable上组合各种LINQ方法的一个例子,它们通常接受某种组合的表达式。因此,带有可选谓词的基本select将是:

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }
使用哪种Northwind进行查询:

SELECT COUNT(*) AS [value]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[Country] = @p0
在查询中包含select投影的问题在于,最终会得到多个泛型类型。由于您经常希望投影是匿名类型,因此很难指定投影类型anonymous和表类型,并且它不可调用

实际上,我想知道写这种方法是否有很多好处。我可能会坚持使用基本方法:

    public IQueryable<T> Get<T>() where T : class
    {
        return (IQueryable<T>)GetTable(typeof(T));
    }
或者,如果您确实希望包含orderby和投影,那么扩展方法是最实用的方法;然后,您不需要指定原始源t,这使得它在与anon类型混合时不可调用:

public static class QueryExtension
{
    public static IQueryable<TProjection>
        Get<TSource, TProjection, TOrderKey>(
            this IQueryable<TSource> source,
            Expression<Func<TSource, bool>> where, // optional
            Expression<Func<TSource, TProjection>> select,
            Expression<Func<TProjection, TOrderKey>> orderBy)
    {
        if (where != null) source = source.Where(where);
        return source.Select(select).OrderBy(orderBy);
    }
}

然后考虑一个DAL方法,例如:

    public List<string> Countries()
    {
        return Customers.Get(
            x=>x.CompanyName != "",
            x=>x.Country,
            x=>x).Distinct().ToList();
    }
再次使用Northwind:

SELECT DISTINCT [t0].[Country]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[CompanyName] <> @p0

您可以使用Linq示例提供的动态表达式库,通过此扩展库,您可以传递where等的Linq子句

可从此处下载

Marc Gravell♦, 和往常一样,它提供了一个非常有见地的答案,但我真的认为,在大多数情况下,使用接受IQueryables并添加限制的方法是可行的,它们使代码更清晰,易于维护。例如:

    using(var ctx = new MyDataContext(CONN))
    {
        ctx.Log = Console.Out;
        int frCount = ctx.Get<Customer>(c => c.Country == "France").Count();
    }
//Join
public static IQueryable<IContract> AllContracts(this IQueryable<IAccount> accounts, ISession s ) {
          return from a in accounts
                 from contract in s.Query<IContract()
                 where (a.Id == contract.AccountId)
                 select contract;
    }
//Where
public static IQueryable<IContract> Active(this IQueryable<IContract> contracts) {
          return from contract in contracts
                 where (contract.Active == true)
                 select contract;
    }
然后你可以像这样混合搭配:

IQueryable<IContract> activeContracts = s.Query<IAccount>()
            .Where(o => o.Name == "XXX")
            .GetContracts(s)
            .Active();

我在这里使用扩展方法和NHiberante的LINQ提供的查询方法,但是这可以很容易地在没有静态方法和任何LINQ提供程序的情况下重写

事实上,我对此有点担心。它编译谓词的事实意味着它将始终加载整个表,然后对其上的对象执行LINQ。这是非常低效的。
//Join
public static IQueryable<IContract> AllContracts(this IQueryable<IAccount> accounts, ISession s ) {
          return from a in accounts
                 from contract in s.Query<IContract()
                 where (a.Id == contract.AccountId)
                 select contract;
    }
//Where
public static IQueryable<IContract> Active(this IQueryable<IContract> contracts) {
          return from contract in contracts
                 where (contract.Active == true)
                 select contract;
    }
IQueryable<IContract> activeContracts = s.Query<IAccount>()
            .Where(o => o.Name == "XXX")
            .GetContracts(s)
            .Active();