使用未知列过滤重复项

问题描述 投票:0回答:1
public async Task<dynamic> GetDuplicants(params string[] selectedColumns)

{
    
    var parameter = Expression.Parameter(typeof(Applicant), "x");
    var properties = selectedColumns.Select(columnName => Expression.Property(parameter, columnName));
    var selector = Expression.Lambda<Func<Applicant, object>>(Expression.NewArrayInit(typeof(object), properties), parameter);
    var duplicates = await _dbContext.Applicants
                                .Where(x => x.Deleted== false)
                                .GroupBy(selector)
                                .Select(group => new
                                {
                                    NumberOfApp = group.Count(),
                                    Columns = group.Key                                      })
                                .Where(result => result.NumberOfApp > 1)
                                .ToListAsync();

    return duplicates;

}

无法翻译。附加信息:查询包含 包含非常量元素的新数组表达式,不能 翻译为:'新对象[]

我期待指定列上有重复项。

c# oracle linq .net-core entity-framework-core
1个回答
0
投票

我对你的函数做了一些调整,以增强其灵活性。它现在返回一个 DuplicatesInfo 列表,其中列转换为字符串。

为了简化动态查询生成,我使用了带有“|”的字符串连接作为分隔符来创建可翻译的键。实现后,我拆分密钥以检索字符串值。

以下是如何使用该功能:

var result = await _dbContext.Applicants
    .Where(x => x.Deleted == false)
    .GetDuplicantsAsync(selector)
    .ToListAsync();

这是实现:

public static class QueryableExtensions
{
    public class DuplicatesInfo
    {
        public string[] Keys { get; set; } = default!;
        public int Count { get; set; }
    }

    public static async Task<List<DuplicatesInfo>> GetDuplicantsAsync<T>(this IQueryable<T> query, params string[] selectedColumns)
    {
        var keySelector = GenerateKeyFunction<T>(selectedColumns);

        var duplicates = await query
            .GroupBy(keySelector)
            .Select(group => new
            {
                Count = group.Count(),
                Columns = group.Key
            })
            .Where(s => s.Count > 1)
            .ToListAsync();

        var result = duplicates.Select(d => new DuplicatesInfo
        {
            Keys = d.Columns.Split('|'),
            Count = d.Count
        }).ToList();

        return result;
    }

    static MethodInfo _stringConcatMethodInfo = typeof(string).GetMethods()
        .Single(m =>
            m.Name == nameof(string.Concat) && m.GetParameters().Length == 2 &&
            m.GetParameters()[0].ParameterType == typeof(string) &&
            m.GetParameters()[1].ParameterType == typeof(string)
        );


    static Expression<Func<T, string>> GenerateKeyFunction<T>(IEnumerable<string> propertyNames)
    {
        Expression<Func<string, string, string>> concat = (s1, s2) => s1 + "|" + s2;

        var entityParam = Expression.Parameter(typeof(T), "e");

        var keyBody = propertyNames
            .Select(p => (Expression)Expression.PropertyOrField(entityParam, p))
            .Select(p => p.Type == typeof(string) ? p : Expression.Call(typeof(Convert), nameof(Convert.ToString), Type.EmptyTypes, p))
            .Aggregate((prev, next) => Expression.Add(Expression.Add(prev, Expression.Constant("|"),_stringConcatMethodInfo), next, _stringConcatMethodInfo));

        var lambda   = Expression.Lambda<Func<T, string>>(keyBody, entityParam);

        return lambda;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.