在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 ()
不行,因为你需要把所有的数据运回数据库来完成最后的部分。
通常,您有一个额外的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()将执行查询。函数之后我们处理的是对象而不是数据库