是否可以将Linq中的lambda参数化为实体选择

时间:2016-06-10 13:37:09

标签: c# entity-framework linq-to-entities entity-framework-6

我有2个实体框架查询,除了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,
    });

我尝试创建一个扩展方法来共享没有func参数的select,但是抛出异常然后我使用location param:

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

我看到了他的错误信息:

  

LINQ表达式节点类型&#39;调用&#39; LINQ to Entities不支持。

2 个答案:

答案 0 :(得分:1)

将此语法与let语句一起使用,以便一举实现合成。您需要一个基类或更好的接口,以实现您的出发和返回实体之间的通用性。

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,
    };

答案 1 :(得分:0)

而不是使用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,                    
        });
    }

Explanation:

ToExpandableDLINQ Table对象周围创建一个瘦包装器。感谢这个包装器,您可以使用名为Invoke的第二个方法扩展Expression类以调用lambda表达式,同时仍然可以将查询转换为T-SQL。这是有效的,因为在转换为表达式树时,包装器会将所有出现的Invoke方法替换为调用的lambda表达式的表达式树,并将这些表达式传递给能够将扩展查询转换为T-SQL的DLINQ。 / p>