Actually it is easy without any non wanted roundtrips to database. LINQ is very cool.
var valuesQuery = CreateValuesQuery<Guid>(ctx, (e, p) =>
p.PropertyInfo.GetCustomAttributes().Any(a => a is MyCustomAttribute));
if (valuesQuery != null)
{
var userInfoQuery =
from ui in dbContext.UserInfoTable
join v in valuesQuery on ui.UserId equals v
select ui;
var infoResut = userInfoQuery.ToList();
}
And implementation:
public static IQueryable<T> CreateValuesQuery<T>(DbContext ctx, Func<IEntityType, IProperty, bool> filter)
{
Expression query = null;
IQueryProvider provider = null;
var ctxConst = Expression.Constant(ctx);
foreach (var entityType in ctx.Model.GetEntityTypes())
{
ParameterExpression entityParam = null;
foreach (var property in entityType.GetProperties().Where(p => p.ClrType == typeof(T) && filter(entityType, p)))
{
entityParam ??= Expression.Parameter(entityType.ClrType, "e");
var setQuery = Expression.Call(ctxConst, nameof(DbContext.Set), new[] {entityType.ClrType});
provider ??= ((IQueryable) Expression.Lambda(setQuery).Compile().DynamicInvoke()).Provider;
var propertyLambda = Expression.Lambda(Expression.MakeMemberAccess(entityParam, property.PropertyInfo), entityParam);
var projection = Expression.Call(typeof(Queryable), nameof(Queryable.Select), new[]
{
entityType.ClrType,
typeof(T)
},
setQuery,
propertyLambda
);
if (query != null)
query = Expression.Call(typeof(Queryable), nameof(Queryable.Union), new []{typeof(T)}, query, projection);
else
query = projection;
}
}
if (query == null)
return null;
return provider.CreateQuery<T>(query);
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…