2

私はこの単純なクラスを持っています:

public class JDEItemLotAvailability
    {
        public string Code { get; set; }
        public int ShortCode { get; set; }
        public string Description { get; set; }
        public string PrimaryUnitCode { get; set; }
        public string BranchPlant { get; set; }
        public string Location { get; set; }
        public string Lot { get; set; }
        public int AvailableQuantity { get; set; }
    }

私の BLL のこの DAL メソッドは、それらのリストを返します。

var returnedLotList = _JDE8dal.GetLotAvailabilityAsList(_lot);

返されたリストで次のことを実行したいのですが、最も「エレガントな」LINQ の方法で実行したいと考えています。

リストの中に特定の条件に一致するレコードがあるかどうかを確認したい。私は次のようなことを考えました:

  var query =
      returnedLotList.Where(l => l.AvailableQuantity != 0 && l.BranchPlant == _mcu && l.Location == _locn)
                               .OrderByDescending(l => l.AvailableQuantity);

しかし、上記のクエリが結果を返さない場合は、残りのリストエントリの最初のものを取得したいと言いたいです。

どうやってやるの?

4

3 に答える 3

3

あなたはただ使うことができますDefaultIfEmpty

//your first query, unaltered
var query =
      returnedLotList.Where(l => l.AvailableQuantity != 0 && l.BranchPlant == _mcu && l.Location == _locn)
                               .OrderByDescending(l => l.AvailableQuantity);

var query2 = query.DefaultIfEmpty(returnedLotList.Take(1));
于 2012-12-18T17:58:24.717 に答える
0

これを行う拡張メソッドを作成できます。

public static IEnumerable<T> WhereOrFirstOfRest<T>(
    this IEnumerable<T> collection, Func<T, bool> predicate)
{
    var filtered = collection.Where(predicate);

    return filtered.Any() ? filtered : collection.Take(1);
}

この拡張メソッドの欠点は、コレクションを複数回反復することです。これは、(たとえばデータベースからの) ストリームを処理しているときに問題になる可能性があります。より効率的な方法は次のとおりです。

public static IEnumerable<T> WhereOrFirstOfRest<T>(
    this IEnumerable<T> collection, Func<T, bool> predicate)
{
    // Materialize the complete collection.
    collection = collection.ToArray();

    // Filter the collection. ToArray prevents calling the predicate
    // twice for any item.
    var filtered = collection.Where(predicate).ToArray();

    return filtered.Any() ? filtered : collection.Take(1);
}

これにより、データベースへの余分な呼び出しを回避できますが、隠れた場所にいくつかの新しい配列が作成されます。したがって、最も効率的な方法は次のとおりです。

public static IEnumerable<T> WhereOrFirstOfRest<T>(
    this IEnumerable<T> collection, Func<T, bool> predicate)
{
    T firstItem = default(T);
    bool firstStored = false;
    bool predicateReturnedItems = false;

    foreach (var item in collection)
    {
        if (!firstStored)
        {
            firstItem = item;
            firstStored = true;   
        }

        if (predicate(item))
        {
            yield return item;
            predicateReturnedItems = true;
        }
    }

    if (!predicateReturnedItems && !first)
    {
        yield return firstItem;
    }
}
于 2012-12-18T17:57:44.793 に答える
0

よくわかりませんが、おそらく次のようなものです。

var firstMatch = returnedLotList.FirstOrDefault(l => l.AvailableQuantity != 0 && 
                                                     l.BranchPlant == _mcu && 
                                                     l.Location == _locn);
if (firstMatch != null)
    return firstMatch;
int max = returnedLotList.Max(l => l.AvailableQuantity);
return returnedLotList.First(l => l.AvailableQuantity == max);
  • 一致しない場合、FirstOrDefault は null を返します
  • 何が起こっているのかを明確にするために、クエリを分割することをお勧めします。
于 2012-12-18T17:59:40.550 に答える