在IQueryable中执行函数

本文关键字:函数 执行 IQueryable | 更新日期: 2023-09-27 18:03:05

使用Linq,可以很容易地执行一个函数来投影IEnumerable。

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

使用EntityFramework和IQueryable,这是不可能的。相反,你会在运行时得到一个不支持的异常,因为你不能在Select中使用函数。

不工作:

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

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

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

数据库只会拉> 50和TOP 10,只有在这之后才会是

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

澄清一下:要求是在select ()

在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.AsQueryable,其中确实IEnumerable<T>生成IQueryable<T> -但它不做您想要的。如果源不是一个真正的可查询对象,它将"伪造"它,但不会将其连接回数据库,这就是您所需要的。

是的,这是可能的,但您必须稍微扭转一下局面:

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);

当然可以像下面这样调用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()将执行查询。函数之后我们处理的是对象而不是数据库