是否可以在 Linq to Entities 中参数化 lambda Select
Is it possible to parameterise a lambda in Linq to Entities Select
我有 2 个 entity framework 查询,除了 2 个属性的 lambda 之外几乎完全相同; Select()
方法中的位置和日期时间。
var departQuery = _dataContext
.Job
.Where(j => j.Departure.DateTime >= startDate && j.Departure.DateTime <= endDate)
.Select(j => new DispatchDashboardItem()
{
JobId = j.Id,
Direction = "PickUp",
CustomerName = j.Driver.Name,
Vehicle = j.Vehicle,
Location = j.Departure.MeetingLocation.Name,
DateTime = j.Departure.DateTime,
});
var returnQuery = _dataContext
.Job
.Where(j => j.Return.DateTime >= startDate && j.Return.DateTime <= endDate)
.Select(j => new DispatchDashboardItem()
{
JobId = j.Id,
Direction = "DropOff",
CustomerName = j.Driver.Name,
Vehicle = j.Vehicle,
Location = j.Return.MeetingLocation.Name,
DateTime = j.Return.DateTime,
});
我尝试创建一个扩展方法来共享 select,它可以在没有 func 参数的情况下工作,但会抛出异常,然后我使用位置参数:
public static IQueryable<DashboardItem> SelectDashboardItem(this IQueryable<Job> query,
string direction,
Func<Job, MeetingDetail> location)
{
return query
.Select(j => new DashboardItem()
{
JobId = j.Id,
Direction = direction,
CustomerName = j.Driver.Name,
Vehicle = j.Vehicle,
// This works without using the func
Location = location(j).MeetingLocation.Name,
DateTime = location(j).DateTime,
});
}
我看到他的错误信息:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
不要使用 Func
作为参数,而是使用 Expression
。传递您用作参数的相同 lambda 表达式,它将隐式转换。现在要实现您需要的功能,您需要使用 LinqKit 库:
public static IQueryable<DashboardItem> SelectDashboardItem(this IQueryable<Job> query,
string direction,
Expression<Func<Job, MeetingDetail>> location)
{
return query.AsExpandable()
.Select(j => new DashboardItem()
{
JobId = j.Id,
Direction = direction,
CustomerName = j.Driver.Name,
Vehicle = j.Vehicle,
// This works without using the func
Location = location.Invoke(j).MeetingLocation.Name,
DateTime = location.Invoke(j).DateTime,
});
}
ToExpandable
在 DLINQ Table 对象周围创建一个薄包装。多亏了这个包装器,您可以使用名为 Invoke
的第二种方法,它扩展了 Expression
class 来调用 lambda 表达式,同时仍然可以将查询转换为 T-SQL。这是有效的,因为当转换为表达式树时,包装器用调用的 lambda 表达式的表达式树替换所有出现的 Invoke
方法,并将这些表达式传递给能够将扩展查询转换为 T-[=27 的 DLINQ =].
将此语法与let语句结合使用,一举实现合成。您需要一个基础 class,或者更好的接口,用于您的 Departure 和 Return 实体之间的共性。
var query = from job in _dataContext.Job
let departureOrReturn = (direction == "PickUp" ? job.Departure : job.Return) as BaseReturnOrDeparture
where (departureOrReturn.DateTime >= startDate && departureOrReturn.DateTime <= endDate)
select new DispatchDashboardItem
{
JobId = job.Id,
Direction = direction,
CustomerName = job.Driver.Name,
Vehicle = job.Vehicle,
Location = deptartureOrReturn.MeetingLocation.Name,
DateTime = deptartureOrReturn.DateTime,
};
我有 2 个 entity framework 查询,除了 2 个属性的 lambda 之外几乎完全相同; Select()
方法中的位置和日期时间。
var departQuery = _dataContext
.Job
.Where(j => j.Departure.DateTime >= startDate && j.Departure.DateTime <= endDate)
.Select(j => new DispatchDashboardItem()
{
JobId = j.Id,
Direction = "PickUp",
CustomerName = j.Driver.Name,
Vehicle = j.Vehicle,
Location = j.Departure.MeetingLocation.Name,
DateTime = j.Departure.DateTime,
});
var returnQuery = _dataContext
.Job
.Where(j => j.Return.DateTime >= startDate && j.Return.DateTime <= endDate)
.Select(j => new DispatchDashboardItem()
{
JobId = j.Id,
Direction = "DropOff",
CustomerName = j.Driver.Name,
Vehicle = j.Vehicle,
Location = j.Return.MeetingLocation.Name,
DateTime = j.Return.DateTime,
});
我尝试创建一个扩展方法来共享 select,它可以在没有 func 参数的情况下工作,但会抛出异常,然后我使用位置参数:
public static IQueryable<DashboardItem> SelectDashboardItem(this IQueryable<Job> query,
string direction,
Func<Job, MeetingDetail> location)
{
return query
.Select(j => new DashboardItem()
{
JobId = j.Id,
Direction = direction,
CustomerName = j.Driver.Name,
Vehicle = j.Vehicle,
// This works without using the func
Location = location(j).MeetingLocation.Name,
DateTime = location(j).DateTime,
});
}
我看到他的错误信息:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
不要使用 Func
作为参数,而是使用 Expression
。传递您用作参数的相同 lambda 表达式,它将隐式转换。现在要实现您需要的功能,您需要使用 LinqKit 库:
public static IQueryable<DashboardItem> SelectDashboardItem(this IQueryable<Job> query,
string direction,
Expression<Func<Job, MeetingDetail>> location)
{
return query.AsExpandable()
.Select(j => new DashboardItem()
{
JobId = j.Id,
Direction = direction,
CustomerName = j.Driver.Name,
Vehicle = j.Vehicle,
// This works without using the func
Location = location.Invoke(j).MeetingLocation.Name,
DateTime = location.Invoke(j).DateTime,
});
}
ToExpandable
在 DLINQ Table 对象周围创建一个薄包装。多亏了这个包装器,您可以使用名为 Invoke
的第二种方法,它扩展了 Expression
class 来调用 lambda 表达式,同时仍然可以将查询转换为 T-SQL。这是有效的,因为当转换为表达式树时,包装器用调用的 lambda 表达式的表达式树替换所有出现的 Invoke
方法,并将这些表达式传递给能够将扩展查询转换为 T-[=27 的 DLINQ =].
将此语法与let语句结合使用,一举实现合成。您需要一个基础 class,或者更好的接口,用于您的 Departure 和 Return 实体之间的共性。
var query = from job in _dataContext.Job
let departureOrReturn = (direction == "PickUp" ? job.Departure : job.Return) as BaseReturnOrDeparture
where (departureOrReturn.DateTime >= startDate && departureOrReturn.DateTime <= endDate)
select new DispatchDashboardItem
{
JobId = job.Id,
Direction = direction,
CustomerName = job.Driver.Name,
Vehicle = job.Vehicle,
Location = deptartureOrReturn.MeetingLocation.Name,
DateTime = deptartureOrReturn.DateTime,
};