对不重复的实体列表的所有属性执行 LINQ 搜索

Performing a LINQ search on all properties of a list of entities without duplicates

我需要对数据集执行 LINQ 搜索,以查找搜索键与所有列中存在的所有值匹配的所有数据行。例如,我在数据网格中有一个这样的数据集:

    Province        Code    Region
    ==================================
    Alessandria     AL      Piemonte
    Aosta           AO      Valle d'Aosta
    Varese          VA      Lombardia

在代码中表示为 List<Province> tableData,搜索关键字存储在 param.Search.Value 中。在下面的代码中,我过滤了网格的所有可搜索列并在 tableData

上执行搜索
    if (param.Search != null && !string.IsNullOrEmpty(param.Search.Value))
    {
        var columns = param.Columns.GetAllSearchableColumns();
        searchedData.AddRange(param.SelectMatchingData(tableData, columns));
    }

我使用两个扩展来执行搜索:

    public static IEnumerable<T> SelectMatchingData<T>(this IDataTablesRequest param, IEnumerable<T> tableData, List<Column> columns)
    {
        return tableData.SelectMany(entity => columns, (entity, column) => new { entity, column })
            .Select(@t => new { @t, isMatch = @t.entity.GetMatchingValue(@t.column.Name, param.Search.Value) })
            .Where(@t => @t.isMatch)
            .Select(@t => @t.@t.entity);
    }


    public static bool GetMatchingValue(this object src, string propertyName, string valueToMatch)
    {
        if (src == null)
        {
            return false;
        }

        var propertyValue = src.GetType().GetProperty(propertyName).GetValue(src, null).ToString();
        return propertyValue.Trim().ToLower().StartsWith(valueToMatch.Trim().ToLower());
    }

当我使用 'va' 作为搜索关键字时,结果将是:

    Province        Code    Region
    ==================================
    Aosta           AO      Valle d'Aosta
    Varese          VA      Lombardia
    Varese          VA      Lombardia

因为 Varese 行在值 Varese 和 VA 上匹配。

如何改进我的 LINQ 代码以避免重复?

您可以使用 Distinct() 删除重复项。然而,尽管这样做会 "solve" 问题,但它会掩盖算法的问题:最好不要首先添加重复项,而不是事后消除它们。

您可以更改 SelectMatchingData 以在 Any() 条件下扩展列,避免重复检查:

public static IEnumerable<T> SelectMatchingData<T>(this IDataTablesRequest param, IEnumerable<T> tableData, List<Column> columns) {
    return tableData
        .Where(entity => columns.Any(column => entity.GetMatchingValue(column.Name, param.Search.Value)));
}