NHibernate和运行时表达式

时间:2017-09-06 13:30:59

标签: c# .net nhibernate

我为从db获取的实体编写访问权限检查器。 我已经声明了基本规则类:

abstract class AccessRule
{
    private Func<object, Entities.User, bool> _canViewCompiledExpression;

    public abstract Expression<Func<object, Entities.User, bool>> RawCanEditExpression { get; }
    public abstract Type ObjectType { get; }
    public Expression<Func<object, bool>> CreateCanViewExpression(AccessContext accessContext, Entities.User user)
    {
        var entityArgument = Expression.Parameter(typeof(object), "arg1");
        var userExpression = Expression.Constant(user, typeof(Entities.User));
        var body = Expression.Invoke(RawCanViewExpression, entityArgument, userExpression);

        return (Expression<Func<object, bool>>)Expression.Lambda(body, entityArgument);
    }
   }

  abstract class AccessRule<T> : AccessRule
    where T : Entity
  {
    public override Type ObjectType => typeof(T);

    public abstract Expression<Func<T, Entities.User, bool>> CanViewExpression { get; }
    public override Expression<Func<object, Entities.User, bool>> RawCanViewExpression => ExpressionHelper.BoxExpression(CanViewExpression);    
   }

这是转换表达式&gt;的帮手。到表达式&gt;:

public static Expression<Func<object, Entities.User, bool>> BoxExpression<T>(Expression<Func<T, Entities.User, bool>> expression)
{
    var objParameter = Expression.Parameter(typeof(object), "arg1");
    var userParameter = Expression.Parameter(typeof(Entities.User), "arg2");

    var convertExpression = Expression.Convert(objParameter, typeof(T));

    var body = Expression.Invoke(expression, convertExpression, userParameter);
    var result = Expression.Lambda<Func<object, Entities.User, bool>>(body, objParameter, userParameter);

    return result;
}

现在,例如一个规则,对于一个项目:

public override Expression<Func<Entities.Order, Entities.User, bool>> CanViewExpression
        => (obj, user) => obj.Owner == user;

现在我将我的表达式(包装到规范类)应用于DB的查询。我根据此代码https://github.com/rjperes/DevelopmentWithADot.NHibernateSpecifications/blob/master/DevelopmentWithADot.NHibernateSpecifications/SpecificationExtensions.cs

从表达式中提取所有条件(例如Expression&gt;,Expression&gt;,MethodCallExpression和UnaryExpression)

并将其应用于Query&lt;&gt;方法

我通过将结果表达式编译为Func并对数据库上的每个项目进行调用来检查结果表达式。一切都好。 但后来我在真实连接上执行查询我在NHibertante核心代码中捕获NullReferenceException。

经过调查我发现在NHibernate.Linq.Visitors.ExpressionKeyVisitor.VisitConstantExpression方法中生成异常,因为_constantToParameterMap为null但未经任何检查使用:

protected override Expression VisitConstantExpression(ConstantExpression expression)
{
    NamedParameter param;

    if (_constantToParameterMap.TryGetValue(expression, out param) && insideSelectClause == false)
从NHibernate.Linq.Visitors.WhereJoinDetectors.VisitMemberExpression方法传递

null

var key = ExpressionKeyVisitor.Visit(expression, null);

我使用了NHIbernate 4.1.1

任何人都可以帮忙解决这个问题吗?

更新1 这是结果表达式的调试视图:

.Lambda #Lambda1<System.Func`2[System.Object,System.Boolean]>(System.Object $arg1) {
    .Invoke (.Lambda #Lambda2<System.Func`3[System.Object,Project.Entities.User,System.Boolean]>)(
        $arg1,
        .Constant<Project.Entities.User>(Project.Entities.User))
}

.Lambda #Lambda2<System.Func`3[System.Object,Project.Entities.User,System.Boolean]>(
    System.Object $arg1,
    Project.Entities.User $arg2) {
    .Invoke (.Lambda #Lambda3<System.Func`3[Project.Entities.Order,Project.Entities.User,System.Boolean]>)(
        (Project.Entities.Windfarm)$arg1,
        $arg2)
}

.Lambda #Lambda3<System.Func`3[Project.Entities.Order,Project.Entities.User,System.Boolean]>(
    Portal.Domain.Entities.Windfarm $obj,
    Portal.Domain.Entities.User $user) {
    .Call($obj.Owner).Equeal($user)
}

更新2 经过一些实验后,我发现只有当我尝试访问规则内的用户时才会发生错误...即如果我用表达式替换check,则不包含对用户的访问权限。所以问题在于不断表达,但我无法理解为什么以及如何解决它

1 个答案:

答案 0 :(得分:0)

好的,最后我找到了解决方案。我没有发现任何这种行为的原因...... 首先,我是检查表达式,由我的代码和代码中的等价表达式生成。我的表达式包含调用其他表达式的主要区别,它调用其他表达式(我们需要更深入),但在编码表达式中没有嵌套项目。

所以我写了一些表达式访问者:首先是表达式的更改参数,然后将其转换为表达式中的原始类型,第二个用于将表达式的参数替换为常量。

现在一切都很完美!