簡體   English   中英

LINQ查詢合並2個結果集

[英]LINQ query to combine 2 resultsets

我有一個C#LINQ查詢,該查詢具有一個主查詢,然后根據變量是否未設置0進行其他2個查詢。

該查詢正在運行,但是我需要合並結果集並返回它。

我希望最終結果集包含兩個子查詢的結果組合。 有點像在SQL查詢中,您擁有:

SELECT * FROM myTable WHERE column1 = 'abc' OR column2 = 'xyz'

現在,我認為它使用的是AND而不是OR

var GeoLocations = rows.Select(r => new ElementSearchGeoLocation(r))
    .Where(t => (t.GeoLocationType == "State" && t.CanViewState(t.GeoLocationState, user)) ||
                (t.GeoLocationType == "City" && t.CanViewCity(t.GeoLocationCity, user)));

if(SystemList != 0)
{
    GeoLocations = GeoLocations.Where(t => (dto.SystemList.Contains(t.SystemID)));
}

if (groupList != 0)
{
    GeoLocations = GeoLocations.Where(t => (dto.groupList.Contains(t.PoliticalID)));
}

return Ok(GeoLocations);

有沒有辦法在LINQ中做到這一點?

這是PredicateBuilder的實現,該實現能夠將兩個不同的表達式Or在一起。

public static class PredicateBuilder
{
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> False<T>() { return f => false; }

    public static Expression<Func<T, bool>> Or<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var secondBody = expr2.Body.Replace(
            expr2.Parameters[0], expr1.Parameters[0]);
        return Expression.Lambda<Func<T, bool>>
              (Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
    }

    public static Expression<Func<T, bool>> And<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var secondBody = expr2.Body.Replace(
            expr2.Parameters[0], expr1.Parameters[0]);
        return Expression.Lambda<Func<T, bool>>
              (Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
    }
}

能夠將一個表達式的所有實例替換為另一個表達式取決於以下代碼:

internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}
internal static class ExpressionExtensions
{
    public static Expression Replace(this Expression expression,
        Expression searchEx, Expression replaceEx)
    {
        return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
    }
}

現在,您可以使用此代碼編寫:

var GeoLocations = rows.Select(r => new ElementSearchGeoLocation(r))
    .Where(t => (t.GeoLocationType == "State" && t.CanViewState(t.GeoLocationState, user)) ||
                (t.GeoLocationType == "City" && t.CanViewCity(t.GeoLocationCity, user)));

var predicate = PredicateBuilder.False();

if(SystemList != 0)
{
    predicate = predicate.Or(t => dto.SystemList.Contains(t.SystemID));
}

if (groupList != 0)
{
    predicate = predicate.Or(t => dto.groupList.Contains(t.PoliticalID));
}

return Ok(GeoLocations.Where(predicate));

兩種方法可以解決此問題

  • Union ,在剔除重復項時合並兩個結果集
  • Concat ,僅將兩個結果集放在一起

您選擇哪一個取決於所需的行為。 請注意,如果您的查詢實際上是IQueryable並從數據庫(通過linq-to-sql或Entity Framework等)運行,則這兩種方法可能有效也可能無效。

如前所述,請不要忘記對LINQ結果進行了延遲評估,並且可以安全地保存查詢的這一部分並將其重新哈希以供以后使用。

使用Concat添加其他行。 為了使代碼極少,我將存儲最初的“首先選擇”:

var AllLocations = rows.Select(r => new ElementSearchGeoLocation(r));
var mainQuery = AllLocations.Where(t => (t.GeoLocationType == "State" && t.CanViewState(t.GeoLocationState, user)) ||
                        (t.GeoLocationType == "City" && t.CanViewCity(t.GeoLocationCity, user)));

然后:

IEnumerable<GeoLocation> subQuery;
if (SystemList != 0)
   subQuery = AllLocations.Where(...);
else
   subQuery = AllLocations.Where(...);

var GeoLocations = mainQuery.Concat(subQuery);

如果您關心重復項,則可以在最后一步中使用Union而不是Concat

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM