有關如何使此 LINQ 查詢更高效的任何建議?我最近創建了 formattedDate 變數,因為之前我多次呼叫 GetDateInFormat。
if (customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.Where(ol => ol.DateTypeId == "OrderPickUpFrom" && ol.ActualDate != null)
.Any())
{
var date = customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.OrderBy(d => d.ActualDate)
.FirstOrDefault(d => d.DateTypeId == "OrderPickUpFrom" && d.ActualDate != null)
.ActualDate;
if (date != null)
{
var formattedDate = _dateHelper.GetDateInFormat("DD/MM/YYYY", date);
order.ArriveDate = formattedDate;
order.EarliestShipDate = formattedDate;
order.EarliestDeliveryDate = formattedDate;
order.EarliestApptTime = _dateHelper.GetDateInFormat("HHMM", date);
}
}
customerOrder 是一個客戶訂單類。
public class Order
{
public Order();
public List<OrderLine> OrderLines { get; set; }
}
public class OrderLine
{
public OrderLine();
public List<OrderDate> OrderDates { get; set; }
}
public class OrderDate
{
public OrderDate();
public DateTimeOffset? ActualDate { get; set; }
public string DateTypeId { get; set; }
}
uj5u.com熱心網友回復:
好吧,
首先讓我們連續去掉兩個Linq 查詢:
Any()然后FirstOrDefault. 我們可以只執行FirstOrDefault(或其等效項),如果我們得到null,我們就會知道Any回傳false(即我們沒有專案)。其次,我們對整個
OrderBy可列舉項進行排序,然后我們洗掉除一項之外的所有項。我們在浪費資源。是更經濟的方式:我們不需要排序而是掃描列舉并回傳一個或最小的。AggregatenullActualDate
代碼:
var date = customerOrder
.OrderLines
.SelectMany(ol => ol.OrderDates)
.Where(ol => ol.DateTypeId == "OrderPickUpFrom" && ol.ActualDate != null)
.Select(ol => ol.ActualDate)
.Aggregate((DateTimeOffset?) null,
(s, a) => !s.HasValue || s.Value > a ? a : s);
if (date.HasValue) {
var formattedDate = _dateHelper.GetDateInFormat("DD/MM/YYYY", date);
order.ArriveDate = formattedDate;
order.EarliestShipDate = formattedDate;
order.EarliestDeliveryDate = formattedDate;
order.EarliestApptTime = _dateHelper.GetDateInFormat("HHMM", date);
}
uj5u.com熱心網友回復:
首先,如果您不先呼叫資料庫兩次,您可以將執行時間縮短近一半,然后在 if 中呼叫它:
customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.Where(ol => ol.DateTypeId == "OrderPickUpFrom" && ol.ActualDate != null).Any())
而不是在真正的分支中:
var date = customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.OrderBy(d => d.ActualDate)
.FirstOrDefault(d => d.DateTypeId == "OrderPickUpFrom" && d.ActualDate != null).ActualDate;
如果您查看它們實際上是相同的,則可以使用以下方法獲得相同的結果:
var date = customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.OrderBy(d => d.ActualDate)
.Where(d => d.DateTypeId == "OrderPickUpFrom" && d.ActualDate != null)
.Select(x => x.ActualDate)
.FirstOrDefault();
現在 date 中的 null 值將作為 if 陳述句的基礎
if(date != null) {
// do your stuff
}
除此之外,您可以在涵蓋您的查詢的資料庫上創建一個索引,以便包含 DataTypeId 和 ActualDate。
uj5u.com熱心網友回復:
所以你有一個customerOrder. 此 customerOrder 有零個或多個OrderLines。每個 OrderLine 都有零個或多個OrderDates。
從 CustomerOrder 您只對 all 感興趣OrderDates。Order 或 OrderLines 的其余部分對您來說并不有趣。
每個 OrderDate 都有屬性DateTypeId和ActualDate. 在此 customerOrder 深處提到的所有 OrderDate 中,您想查看是否至少有一個 OrderDate 的屬性 DateTypeId 的值等于“OrderPickUpFrom”,并且屬性 ActualDate 的值不為空。
如果根本沒有 OrderDate 匹配,您就沒有定義您想要的內容。
如果其中一個 OrderDate 符合此要求,則采用最舊的匹配 OrderDate 的 ActualDate,如果沒有匹配的 OrderDate,則為 null
您曾經
Any()檢查過至少有一個 OrderDate 的屬性 DateTypeId 的值等于“OrderPickUpFrom”并且屬性 ActualDate 的值不為空。因此,您知道至少有一個匹配的 OrderDate,因此至少有一個匹配的 ActualDate。因此,您知道那date永遠不會為空。
const string requiredDateTypeId = "OrderPickupFrom";
var date = customerOrder.OrderLines
.SelectMany(orderLine => orderline.OrderDate)
.Where(orderDate => orderDate.DateTypeId == requiredDateTypeId
&& orderDate.ActualDate != null)
.OrderBy(orderDate => orderDate.ActualDate)
.Select(orderDate => orderDate.ActualDate)
.FirstOrDefault();
用一句話來說:
從 customerOrder 中,將所有 OrderDates 中的所有 OrderDates 放在該 customerOrder 的所有 OrderLines 中。
僅保留屬性 DateTypeId 的值等于所需 DateTypeId 并且 ActualDate 具有非空值的 OrderDates。
按 ActualDate 的升序對剩余的 OrderDates 進行排序。所以最老的 ActualDate 的 OrderDate 是第一個
從排序的 OrderDates 中,選擇屬性 ActualDate 的值
保留第一個,如果沒有任何具有所需值的 OrderDate,則保留為 null。
if (date != null) { var formattedDate = etc.
現在,您可以做一件事來提高 LINQ 的效率:如果您只打算使用 ActualDate 值最舊的一個,為什么要對所有 OrderDate 進行排序。換句話說:如果您找到了最舊的,則不需要對任何在最舊之后的 OrderDates 進行排序。實際上,您希望有一些Min功能,您可以在其中定義查找最小值的屬性。
為此,我使用了擴展方法。如果您不熟悉擴展方法,請閱讀擴展方法揭秘
public static MinOrDefault<T, TProperty> Min(this IEnumerable<T> source,
Func<T, TProperty> propertySelector)
{
return MinOrDefault(source, propertySelector, null);
}
public static MinOrDefault<T, TProperty> Min(this IEnumerable<T> source,
Func<T, TProperty> propertySelector,
IComparer<TProperty> comparer)
{
// TODO: check source and propertySelector not null
if (comparer == null) comparer = Comparer<TProperty>.Default;
using (IEnumerator<T> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
// There is at least one element in source
T minValue = enumerator.Current;
TProperty minPropertyValue = propertySelector(minValue);
// check the rest of the sequence
while (enumerator.MoveNext())
{
// there is a next. Is the property smaller?
T value = enumerator.Current;
TProperty propertyValue = propertySelector(value);
if (comparer.Compare(propertyValue, minPropertyValue) < 0)
{
// propertyValue is smaller than minPropertyValue
minValue = value;
minPropertyValue = propertyValue;
}
// else: minValue is still the smallest; do nothing
}
// if here, enumerated to the end of the sequence
return minValue;
}
else
{
// empty sequence, return default:
return default(T);
}
}
}
您的代碼將是:
OrderDate oldestOrderDate = customerOrder.OrderLines
.SelectMany(orderLine => orderline.OrderDate)
.Where(orderDate => orderDate.DateTypeId == requiredDateTypeId
&& orderDate.ActualDate != null)
.MinOrDefault(orderDate => orderDate.ActualDate);
if (oldestOrderDate != null)
{
etc.
uj5u.com熱心網友回復:
我建議使用.SelectMany(),.Where()如下.Min():
var date = customerOrder.OrderLines
.SelectMany(ol => ol.OrderDates)
.Where(ol => ol.DateTypeId == "OrderPickUpFrom")
.Min(ol => ol.ActualDate);
.Min()null當結果.Where()為空時將回傳。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/428908.html
