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;
}
无法翻译。附加信息:查询包含 包含非常量元素的新数组表达式,不能 翻译为:'新对象[]
我期待指定列上有重复项。
我对你的函数做了一些调整,以增强其灵活性。它现在返回一个 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;
}
}