Meh*_*iny 8 c# linq reflection design-patterns entity-framework-5
我正在使用EF5,工作单元和存储库模式.我想为访问指定用户的数据定义一些限制.在数据库中,我设计了一个表来保存我的实体名称及其属性(称为EntityProperties),另一个表来保存这些属性的值,这些属性称为PropertyValues,每个EntityProperty都有一个或多个PropertyValues.在用户请求数据的业务层中,如果为他定义了任何限制,则应在linq语句中添加一些条件.我所做的是通过'userId'获取实体名称及其属性和值的列表,然后我在linq查询中添加一些'Where'子句.但是,实体名称及其属性的类型为"String",因此我应该使用Reflection来管理它们.但我不知道这一部分,我不知道 知道如何从给定的条件字符串集创建LINQ where子句.例如,假设用户请求列表顺序,用户ID为5.我首先查询这些访问限制表,结果是:
"订单","Id","74"
"秩序","Id","77"
"订单","Id","115"
这意味着该用户只能看到这三个订单,而在Orders表中,我们有更多的订单.所以,如果我想使用LINQ查询来获取订单,例如:
var orders = from order in Context.Orders
Run Code Online (Sandbox Code Playgroud)
我需要把它变成这样的东西:
var orders = from order in Context.Orders
Run Code Online (Sandbox Code Playgroud)
//其中订单ID应为74,77,115
但是,从"Order"和"Id"字符串到Order实体和Id属性需要反射.因此有两个问题:
从字符串中获取强类型的最佳方法是什么?我有更好的方法来做到这一点,表现更好吗?
好的。通过注释,我们可能会采用类似的方法(假设您在EntityProperties表中有一个导航属性,它是 , 的集合PropertyValues,并命名PropertyValueList(如果没有,只需进行连接而不是使用Include)。
这是一些示例代码,非常质朴,仅适用于 Int32 属性,但这可能是解决方案的开始。
您还可以查看PredicateBuilder ...
反正
我使用“中级”过滤器。
public class Filter
{
public string PropertyName { get; set; }
public List<string> Values { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后是一个辅助类,它将返回一个IQueryable<T>,但是...已过滤
public static class FilterHelper {
public static IQueryable<T> Filter(this IQueryable<T> queryable, Context context, int userId) {
var entityName = typeof(T).Name;
//get all filters for the current entity by userId, Select the needed values as a `List<Filter>()`
//this could be done out of this method and used as a parameter
var filters = context.EntityProperties
.Where(m => m.entityName == entityName && m.userId = userId)
.Include(m => m.PropertyValueList)
.Select(m => new Filter {
PropertyName = m.property,
Values = m.PropertyValueList.Select(x => x.value).ToList()
})
.ToList();
//build the expression
var parameter = Expression.Parameter(typeof(T), "m");
var member = GetContains( filters.First(), parameter);
member = filters.Skip(1).Aggregate(member, (current, filter) => Expression.And(current, GetContains(filter, parameter)));
//the final predicate
var lambda = Expression.Lambda<Func<T, bool>>(member, new[] { parameter });
//use Where with the final predicate on your Queryable
return queryable.Where(lambda);
}
//this will build the "Contains" part
private static Expression GetContains(Filter filter, Expression expression)
{
Expression member = expression;
member = Expression.Property(member, filter.PropertyName);
var values = filter.Values.Select(m => Convert.ToInt32(m));
var containsMethod = typeof(Enumerable).GetMethods().Single(
method => method.Name == "Contains"
&& method.IsGenericMethodDefinition
&& method.GetParameters().Length == 2)
.MakeGenericMethod(new[] { typeof(int) });
member = Expression.Call(containsMethod, Expression.Constant(values), member);
return member;
}
}
Run Code Online (Sandbox Code Playgroud)
用法
var orders = from order in Context.Orders
select order;
var filteredOrders = orders.Filter(Context, 1);//where 1 is a userId
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1234 次 |
| 最近记录: |