简体   繁体   English

将 EF Core WHERE 子句中重复的 Linq OrderBy 转换为更具可读性

[英]Convert duplicated Linq OrderBy in EF Core WHERE clause to be more readable

I am trying to query a list of objects based on the ordering of child items.我正在尝试根据子项的顺序查询对象列表。 I have this query that works, but as you can see the where clause is excessively long because of the duplicated orderby.我有这个有效的查询,但正如您所见,由于重复的 orderby,where 子句过长。

            List<Driver> driversToReturn = new List<Driver>();
        var drivers = await _rwContext.Drivers
            .Include(d => d.RegionIds)
            .Include(d => d.Carrier).ThenInclude(c => c.DriverHolds)
            .Include(m => m.Manifests).ThenInclude(m => m.ManifestStops)
            .ThenInclude(ms => ms.OffloadJourneys).ThenInclude(o => o.EndLocation).ThenInclude(o => o.LocationAliases.Where(la => la.IsPrimary))
            .Include(m => m.Manifests).ThenInclude(m => m.ManifestStops)
            .ThenInclude(ms => ms.OnloadJourneys).ThenInclude(o => o.StartLocation).ThenInclude(o => o.LocationAliases.Where(la => la.IsPrimary))
            .Where(m =>
            ((startDate == null || endDate == null || m.Manifests == null || m.Manifests.Count ==0

            || (m.Manifests.FirstOrDefault(m => m.ManifestStops != null && m.ManifestStops
            .OrderBy(ms => ms.StopTimestamp != null &&
                    ms.StopTimeSet ?
                    ms.StopTimestamp :
                    (!ms.StopTimeSet && ms.StopTimestamp != null ?
                    (ms.IsOffloadStop ?
                    ms.StopTimestamp.Value.AddHours((23 - ms.StopTimestamp.Value.Hour)).AddMinutes((59 - ms.StopTimestamp.Value.Minute)) :
                    ms.StopTimestamp.Value.AddHours(-1 * (ms.StopTimestamp.Value.Hour)).AddMinutes(-1 * (ms.StopTimestamp.Value.Minute))) :
                    (ms.IsOffloadStop ? DateTime.Now.AddYears(10) : DateTime.Now.AddYears(-10)))).ThenBy(ms => ms.IsOffloadStop)
                    .LastOrDefault() != null
            && startDate <= m.ManifestStops
            .OrderBy(ms => ms.StopTimestamp != null &&
                    ms.StopTimeSet ?
                    ms.StopTimestamp :
                    (!ms.StopTimeSet && ms.StopTimestamp != null ?
                    (ms.IsOffloadStop ?
                    ms.StopTimestamp.Value.AddHours((23 - ms.StopTimestamp.Value.Hour)).AddMinutes((59 - ms.StopTimestamp.Value.Minute)) :
                    ms.StopTimestamp.Value.AddHours(-1 * (ms.StopTimestamp.Value.Hour)).AddMinutes(-1 * (ms.StopTimestamp.Value.Minute))) :
                    (ms.IsOffloadStop ? DateTime.Now.AddYears(10) : DateTime.Now.AddYears(-10)))).ThenBy(ms => ms.IsOffloadStop)
                    .LastOrDefault().StopTimestamp
            && endDate.Value.Date.AddDays(1) > m.ManifestStops
            .OrderBy(ms => ms.StopTimestamp != null &&
                    ms.StopTimeSet ?
                    ms.StopTimestamp :
                    (!ms.StopTimeSet && ms.StopTimestamp != null ?
                    (ms.IsOffloadStop ?
                    ms.StopTimestamp.Value.AddHours((23 - ms.StopTimestamp.Value.Hour)).AddMinutes((59 - ms.StopTimestamp.Value.Minute)) :
                    ms.StopTimestamp.Value.AddHours(-1 * (ms.StopTimestamp.Value.Hour)).AddMinutes(-1 * (ms.StopTimestamp.Value.Minute))) :
                    (ms.IsOffloadStop ? DateTime.Now.AddYears(10) : DateTime.Now.AddYears(-10)))).ThenBy(ms => ms.IsOffloadStop)
                    .LastOrDefault().StopTimestamp) == null) &&

            (m.Manifests.FirstOrDefault(m => m.ManifestStops != null && m.ManifestStops
            .OrderBy(ms => ms.StopTimestamp != null &&
                    ms.StopTimeSet ?
                    ms.StopTimestamp :
                    (!ms.StopTimeSet && ms.StopTimestamp != null ?
                    (ms.IsOffloadStop ?
                    ms.StopTimestamp.Value.AddHours((23 - ms.StopTimestamp.Value.Hour)).AddMinutes((59 - ms.StopTimestamp.Value.Minute)) :
                    ms.StopTimestamp.Value.AddHours(-1 * (ms.StopTimestamp.Value.Hour)).AddMinutes(-1 * (ms.StopTimestamp.Value.Minute))) :
                    (ms.IsOffloadStop ? DateTime.Now.AddYears(10) : DateTime.Now.AddYears(-10)))).ThenBy(ms => ms.IsOffloadStop)
                    .FirstOrDefault() != null
            && endDate.Value.Date.AddDays(1) > m.ManifestStops
            .OrderBy(ms => ms.StopTimestamp != null &&
                    ms.StopTimeSet ?
                    ms.StopTimestamp :
                    (!ms.StopTimeSet && ms.StopTimestamp != null ?
                    (ms.IsOffloadStop ?
                    ms.StopTimestamp.Value.AddHours((23 - ms.StopTimestamp.Value.Hour)).AddMinutes((59 - ms.StopTimestamp.Value.Minute)) :
                    ms.StopTimestamp.Value.AddHours(-1 * (ms.StopTimestamp.Value.Hour)).AddMinutes(-1 * (ms.StopTimestamp.Value.Minute))) :
                    (ms.IsOffloadStop ? DateTime.Now.AddYears(10) : DateTime.Now.AddYears(-10)))).ThenBy(ms => ms.IsOffloadStop)
                    .FirstOrDefault().StopTimestamp
            && startDate <= m.ManifestStops
            .OrderBy(ms => ms.StopTimestamp != null &&
                    ms.StopTimeSet ?
                    ms.StopTimestamp :
                    (!ms.StopTimeSet && ms.StopTimestamp != null ?
                    (ms.IsOffloadStop ?
                    ms.StopTimestamp.Value.AddHours((23 - ms.StopTimestamp.Value.Hour)).AddMinutes((59 - ms.StopTimestamp.Value.Minute)) :
                    ms.StopTimestamp.Value.AddHours(-1 * (ms.StopTimestamp.Value.Hour)).AddMinutes(-1 * (ms.StopTimestamp.Value.Minute))) :
                    (ms.IsOffloadStop ? DateTime.Now.AddYears(10) : DateTime.Now.AddYears(-10)))).ThenBy(ms => ms.IsOffloadStop)
                    .FirstOrDefault().StopTimestamp) == null)
            
            )) &&
            
            (m.Carrier == null || m.CarrierId ==0 || m.Carrier.DriverHolds == null || m.Carrier.DriverHolds.Count == 0 ||
            (m.Carrier.DriverHolds.FirstOrDefault(dr => dr.DriverId == m.DriverId &&
            (startDate == null || endDate == null || (dr.StartDate > startDate.Value && dr.StartDate < endDate.Value.Date.AddDays(1))) &&
            (endDate == null || endDate == null || (dr.EndDate > startDate.Value && dr.EndDate < endDate.Value.Date.AddDays(1)))) == null)
            ) && (RegionId == null || m.RegionIds.FirstOrDefault(r => r.RegionId == RegionId) != null))
            .Select(r => new 
            {
                DriverId = r.DriverId,
                DriverTag = r.DriverTag,

                RegionIds = r.RegionIds.Select(r=>new RegionIdItem() {
                    RegionId = r.RegionId,
                    DriverId = r.DriverId
                }),
                Carrier = new {
                    CarrierId = r.Carrier.CarrierId,
                    CarrierTag = r.Carrier.CarrierTag,
                    DriverHolds = r.Carrier.DriverHolds.Where(dh=>dh.DriverId == r.DriverId).Select(dh => new DriverHold() {
                        StartDate = dh.StartDate,
                        EndDate = dh.EndDate,
                        DriverId = dh.DriverId,
                    })
                },
                Manifests = r.Manifests.Select(m => new  {
                    ManifestId = m.ManifestId,
                    ManifestStops = m.ManifestStops                       
                    .Select(ms => new {
                        //manifest stop
                        StopTimeSet = ms.StopTimeSet,
                        StopTimestamp = ms.StopTimestamp,
                        OffloadJourneys = ms.OffloadJourneys.Select(oj => new {
                            EndLocation = new {
                                LocationAliases = oj.EndLocation.LocationAliases.Where(la => la.IsPrimary).Select(la => new LocationAlias()
                                {
                                    Alias = la.Alias,
                                    IsPrimary = la.IsPrimary
                                })
                            }
                        }),
                        //manifest stop
                        OnloadJourneys = ms.OnloadJourneys.Select(oj => new
                        {
                            StartLocation = new
                            {
                                LocationAliases = oj.StartLocation.LocationAliases.Where(la => la.IsPrimary).Select(la => new LocationAlias()
                                {
                                    Alias = la.Alias,
                                    IsPrimary = la.IsPrimary
                                })
                            }
                        })
                    })
                })
            })
            .ToListAsync(ct);

I tried to apply the OrderBy to the 'ThenInclude' where I am selecting 'ManifestStops' but that didn't take effect before the WHERE clause and the ordering was not preserved in the Where query.我尝试将 OrderBy 应用于选择“ManifestStops”的“ThenInclude”,但这在 WHERE 子句之前没有生效,并且排序未保留在 Where 查询中。

I also tried to apply the ordering in the select clause but had the same problem as doing it in the 'ThenInclude'.我还尝试在 select 子句中应用排序,但遇到与在“ThenInclude”中执行此操作相同的问题。

Another approach I attempted was to add an extension method to do this but I got an EF 'Query could not be translated' error.我尝试的另一种方法是添加一个扩展方法来执行此操作,但我收到了一个 EF 'Query could not be translate' 错误。

    public static IEnumerable<ManifestStop> OrderManifestStops(this IEnumerable<ManifestStop> source)
    {

        return source.OrderBy(ms => ms.StopTimestamp != null &&
            ms.StopTimeSet ?
            ms.StopTimestamp :
            (!ms.StopTimeSet && ms.StopTimestamp != null ?
            (ms.IsOffloadStop ?
            ms.StopTimestamp.Value.AddHours((23 - ms.StopTimestamp.Value.Hour)).AddMinutes((59 - ms.StopTimestamp.Value.Minute)) :
            ms.StopTimestamp.Value.AddHours(-1 * (ms.StopTimestamp.Value.Hour)).AddMinutes(-1 * (ms.StopTimestamp.Value.Minute))) :
            (ms.IsOffloadStop ? DateTime.Now.AddYears(10) : DateTime.Now.AddYears(-10)))).ThenBy(ms => ms.IsOffloadStop);
    }

I guess Driver has an implementation close to that我猜Driver有一个接近那个的实现

public class Driver
{
    public DateTime? StopTimestamp { get; set; }   
    public bool StopTimeSet { get; set; }
    public bool IsOffloadStop { get; set; }
}

You can create static field OrderBy您可以创建 static 字段OrderBy

public static Func<Driver, DateTime?> OrderBy 
        = ms => (ms.StopTimestamp != null && ms.StopTimeSet) 
                ? ms.StopTimestamp 
                : (!ms.StopTimeSet && ms.StopTimestamp != null) 
                    ? (ms.IsOffloadStop 
                        ? ms.StopTimestamp.Value.AddHours((23 - ms.StopTimestamp.Value.Hour)).AddMinutes((59 - ms.StopTimestamp.Value.Minute)) 
                        : ms.StopTimestamp.Value.AddHours(-1 * (ms.StopTimestamp.Value.Hour)).AddMinutes(-1 * (ms.StopTimestamp.Value.Minute))) 
                    : ms.IsOffloadStop 
                        ? DateTime.Now.AddYears(10) 
                        : DateTime.Now.AddYears(-10);

And use it, for example like this:并使用它,例如这样:

var drivers = new List<Driver>();


drivers.OrderBy(OrderBy);

But I doubt that it can be translated by EF但是我怀疑它可以被EF翻译

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM