我们有许多包含用户ID属性的实体,我创建了一个自定义属性UserIdAttribute
来注释那些模型。例如:
public class MyEntity
{
[UserId]
public Guid Owner { get; set; }
}
我们将有一个后台服务,其目的是在所有实体中查找用户ID属性,并对它们执行查找以填充另一个表。由于我们的模型/应用程序的状态不断变化,因此我们希望动态地找到这些值。我知道我可以达到Microsoft.Data.SqlClient
以下目的:
var allUserIds = new List<Guid>();
foreach (var entityType in dbContext.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
foreach var attribute in property.PropertyInfo.GetCustomAttributes())
{
if (attribute is MyCustomAttribute)
{
//
// do this using EF & reflection
//
using (var connection = new SqlConnection("my_conn_string"))
{
try
{
var tableName = entityType.GetTableName();
var command = new SqlCommand(
$"select {property.Name} from {tableName}",
conn);
conn.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine($"{entityType.ClrType.Name}.{property.Name}: {reader[property.Name]}");
}
}
finally
{
conn.Close();
}
}
}
}
}
}
PopulateUserInfoTable(allUserIds);
我们更喜欢在这里使用EF,问题是当我只有DbSet名称的字符串表示形式时,我看不到任何查询DbSet的方法。这甚至可以实现吗?
实际上,没有任何不必要的数据库往返都是很容易的。LINQ非常酷。
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();
}
并实现:
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);
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句