使用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可以理解的东西,但是,如果有一个名为'Execute'的扩展方法可以在执行所有linq之前和之后在内存中执行,那工作?
数据库只会拉> 50和只有TOP 10,只有在它之后
var db = new Order(); db.MyEntities.Where(x => x.Id > 50).Execute(x => new SomethingElse(x.Name)).Take(10);
澄清:要求即使在Sleect()
之后仍保持IQueryable答案 0 :(得分:6)
不,因为您需要将所有数据发送回数据库以执行最终部分。
通常你有一个额外的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
,其中 会从IQueryable<T>
生成IEnumerable<T>
- 但它没有做您想做的事情。如果来源不是真正可查询的,那么它将会假冒&#34;假的&#34;但它并没有将它连接回数据库,而这正是你所追求的。
答案 1 :(得分:1)
是的,当然可以调用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()将执行查询。那么我们在那些函数之后所做的就意味着我们正在处理不是数据库的对象。
答案 2 :(得分:1)
是的,这是可能的,但你必须扭转局面:
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()
语句 - 然后您可以按预期使用它。
答案 3 :(得分:0)
您可以构建“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);