在 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.AsQueryable
, 会 从 IEnumerable<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);
使用 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.AsQueryable
, 会 从 IEnumerable<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);