我在 NH Linq 有这样的查询:
var query = _session
.Query<Revision>()
.Join(
_session.Query<Document>(),
rev => rev.Document,
doc => doc,
(rev, doc) => new FolderDocumentRevision { Revision = rev, Document = doc }
).Where(
item => item.Document.OrganisationalUnitRights.Any(cr => (cr.OrganisationalUnit!=null && parentOus.Contains(cr.OrganisationalUnit.Id) ||
cr.RoleId!=null && (_securityInfo.SessionData.Profile.SystemRoleId==cr.RoleId || _securityInfo.SessionData.Profile.ApplicationRoleId==cr.RoleId ))
&& cr.CanView)
);
我正在尝试创建一个扩展以在Where部分中使用HasAccess方法。
query = query.Where(
item => item.Document.OrganisationalUnitRights.HasAccess(SessionFactory,_securityInfo,cr => cr.CanView)
);
花了几个小时,我还是没能完成这个。我遇到的最多问题是转换 Any() 和parentOus.Contains。这是我的出发点:
public class WithRightLinqGenerator : BaseHqlGeneratorForMethod
{
public WithRightLinqGenerator()
{
SupportedMethods = new[]
{
NHibernate.Util.ReflectHelper.GetMethodDefinition<ICollection<OrganisationalUnitRight>>(rights => rights.HasAccess(null, null, null))
};
}
public override HqlTreeNode BuildHql(
MethodInfo method,
Expression targetObject,
ReadOnlyCollection<Expression> arguments,
HqlTreeBuilder treeBuilder,
IHqlExpressionVisitor visitor)
{
var rightsExpression = visitor.Visit(arguments[0]).AsExpression();//visitor.Visit(targetObject).AsExpression();
// The second argument is SessionContainer
var sessionContainerExpression = arguments[1];
var sessionContainerValue = GetConstantValue(sessionContainerExpression) as SessionContainer;
// The third argument is SecurityInfo
var securityInfoExpression = arguments[2];
var securityInfoValue = GetConstantValue(securityInfoExpression) as SecurityInfo;
var parentOus = sessionContainerValue.OUHierarchy.GetAllParents(securityInfoValue.SessionData.Profile.Id).ToList();
var systemRoleId = securityInfoValue.SessionData.Profile.SystemRoleId;
var applicationRoleId = securityInfoValue.SessionData.Profile.ApplicationRoleId;
}
private object GetConstantValue(Expression expression)
{
if (expression is ConstantExpression constantExpression)
{
return constantExpression.Value;
}
// You can extend this method to handle other types of expressions if needed
throw new InvalidOperationException("Expected a constant expression.");
}
}
如何转换此查询?
根据@Svyatoslav Danyliv 的评论,有一种更简单的方法可以解决这个问题。您需要使用 LINQKit 库。然后我创建了两个方法:
[Expandable(nameof(HasAccess))]
public static bool HasAccess(
this ICollection<OrganisationalUnitRight> rights,
SessionContainer sessionFactory,
SecurityInfo securityInfo,
Func<OrganisationalUnitRight, bool> rightSelector
)
{
throw new NotImplementedException();
}
private static Expression<Func<ICollection<OrganisationalUnitRight>,SessionContainer,SecurityInfo,Func<OrganisationalUnitRight, bool> , bool>> HasAccess()
=> (rights,sessionFactory,securityInfo,rightSelector) => rights.Any(
cr =>
(
sessionFactory.OUHierarchy.GetAllParents(securityInfo.SessionData.Profile.Id).Contains(cr.OrganisationalUnit.Id)
|| (
cr.RoleId.HasValue
&& (
securityInfo.SessionData.Profile.SystemRoleId == cr.RoleId
|| securityInfo.SessionData.Profile.ApplicationRoleId == cr.RoleId
)
) && rightSelector(cr)
));
注意,该方法具有 ExpandableAttribute 属性。
现在,当我想在 NH Linq 查询中使用它时,我需要首先调用 AsExpandable() 方法:
query = query.AsExpandable().Where(
item => item.Document.OrganisationalUnitRights.HasAccess(SessionFactory,_securityInfo,cr => cr.CanView)
);