在 IQueryable 中执行函数

Execute Function in IQueryable

使用 Linq,很容易执行函数来投影 IEnumerable。

var orders = new List<Order>();
orders.Where(x => x.Id > 50).Select(x => new SomethingElse(x.Name));

使用 EntityFramework 和 IQueryable,这是不可能的。你反而在运行时得到一个不受支持的异常,因为你不能在 Select.

中有一个函数

Does not work:

var db = new Order();
db.MyEntities.Where(x => x.Id > 50).Select(x => new SomethingElse(x.Name)).Take(10);

是否存在,或者是否有可能为上述工作创建一种方法?

我知道它不起作用,因为它无法将函数转换成 SQL 可以理解的东西,但是,如果有一个名为 'Execute' 的扩展方法可以在执行所有操作后在内存中执行之前和之后的 linq,可以吗?

The database would pull only > 50 AND only TOP 10, only after would it be

var db = new Order();
db.MyEntities.Where(x => x.Id > 50).Execute(x => new SomethingElse(x.Name)).Take(10);

澄清一下:要求即使在 Sleect()

之后也要将其保持为 IQueryable

不,因为您需要将所有数据发送回数据库才能完成最后一部分。

通常您有一个额外的 Select 来获取您在查询中需要的信息(如果您需要多个属性,则使用匿名类型),然后在本地完成其余所有工作:

var query = db.MyEntities
              .Where(x => x.Id > 50)
              .Select(x => x.Name) // All we need - keep the query cheap
              .Take(10)
              .AsEnumerable()
              .Select(x => new SomethingElse(x));

请注意,您可以 运行 转换为 Queryable.AsQueryableIEnumerable<T> 生成 IQueryable<T> - 但它不做你想做的事。如果源不是真正可查询的,它将 "fake" 它但不会将其连接回数据库,这就是您所追求的。

是的,当然可以像下面这样调用 AsEnumerable() 函数:

var db = new Order();
db.MyEntities.Where(x => x.Id > 50)
    .Take(10)
    .AsEnumerable()
    .Execute(x => new SomethingElse(x.Name));

在 Linq 中调用 AsEnumerable()FirstOrDefault()ToList()[= 等函数的实体18=] 将执行查询。所以我们在函数之后所做的意味着我们正在处理对象而不是数据库。

是的,这是可能的,但你必须稍微改变一下:

var db = new Order();
db.MyEntities.Where(x => x.Id > 50)
             .Take(10)
             .AsEnumerable() // This will fetch data from the DB
             .Select(x => new SomethingElse(x.Name)); // Here, data is already fetched

这里的区别在于执行的延迟:Where()Select()Take() 和其他几个操作是延迟的——即在计算整个表达式之前不调用,从而允许整个表达式有效地映射到适当的 SQL 语句。

另一方面,

AsEnumerable() 是非延迟运算符。它允许将输入序列转换为正常的 IEnumerable<T> 序列,从而允许调用标准查询运算符方法。

与其他一些运算符(如 ToList()First() 等)一起,这实际上会导致查询的第一部分在它本身应用之前被执行。在此上下文中,这意味着查询的第一部分被翻译为 SQL 和 运行。结果将传递给下一个运算符 - 您的 Select() 语句 - 然后您可以按预期使用它。

您可以构建 "WHERE":

     Expression<Func<Products, bool>> expresionFinal = p => p.Active;

    if (mydate.HasValue)
    {
        Expression<Func<Products, bool>> expresionDate = p => (EntityFunctions.TruncateTime(c.CreatedDate) <= mydate);
        expresionFinal = PredicateBuilder.And(expresionFinal, expresionDate );
    }

if (!String.IsNullOrEmpty(codeProduct))
                {
                    Expression<Func<Products, bool>> expresionCode = c => (codeProduct== c.codProduct);
                    expresionFinal = PredicateBuilder.And(expresionFinal, expresionCode );
                }

    IQueryable<T> query = dbSet;


        query = query.Where(expresionFinal);