public override Expression MemberExpression(MemberExpression expression) { var type = _persistentClass; MappedClassMetadata mappedClass = null; var members = expression.Members; var lastAliasName = _rootAlias; // If we are inside a lambda expression if (_context.ExpressionLevel > 1) { // Lambda member expression MUST start with a variable name var lambdaContext = _context.FindLambdaContext(members[0].Name); if (lambdaContext == null) { throw new QueryException(ErrorMessages.Expression_LambdaMemberMustStartWithParameter); } type = lambdaContext.ParameterType; lastAliasName = lambdaContext.ParameterAlias; members = members.Skip(1).ToList(); } else if (members[0].Name == "$it") { // Special case: $it variable outside of lambda expression members = members.Skip(1).ToList(); } if (type != null) { _context.SessionFactoryContext.MappedClassMetadata.TryGetValue(type, out mappedClass); } if (members.Count == 1) { Debug.Assert(members[0].IdExpression == null); string resolvedName = ResolveName(mappedClass, string.Empty, members[0].Name, ref type); if (string.IsNullOrEmpty(resolvedName)) { /** * 01.06.2020: Throwing exception moved from "ResolveName" to here. */ throw new QueryException(String.Format( ErrorMessages.Resolve_CannotResolveName, members[0].Name, type) ); } return(new ResolvedMemberExpression( expression.MemberType, (lastAliasName != null ? lastAliasName + "." : null) + resolvedName, type )); } var sb = new StringBuilder(); var typeIsMapped = false; var baseTypeIsMapped = false; for (int i = 0; i < members.Count; i++) { var member = members[i]; Debug.Assert(member.IdExpression == null); bool isLastMember = i == members.Count - 1; string resolvedName = ResolveName(mappedClass, sb.ToString(), member.Name, ref type); /** * 01.06.2020: If the name could not be resolved, then perhaps the type is not mapped? Check whether the type is in our * dictionary of "base type to inherited mapping" and try it again with the type of the mappec class. */ if (string.IsNullOrEmpty(resolvedName)) { typeIsMapped = _context.SessionFactoryContext.MappedClassMetadata.ContainsKey(type); baseTypeIsMapped = _context.SessionFactoryContext.BaseClassToMappedClass.ContainsKey(type); if (!typeIsMapped && baseTypeIsMapped) { type = _context.SessionFactoryContext.BaseClassToMappedClass[type]; } resolvedName = ResolveName(mappedClass, sb.ToString(), member.Name, ref type); if (string.IsNullOrEmpty(resolvedName)) { throw new QueryException(String.Format( ErrorMessages.Resolve_CannotResolveName, members[0].Name, type) ); } } if (sb.Length > 0) { sb.Append('.'); } sb.Append(resolvedName); /** * 01.06.2020: If type is not mapped, check whether the type is the base class of a mapped class. * SessionFactory was extended to hold a dictionary with base type (key) and mapped class type (value). The dictionary will be used * during building ICriteria if searched type is not mapped, but exists as key in this dictionary. This behavior is required if base * controller classes are used and model classes are overwritten and the inherited models are mapped. If the base model are queried * and filtered by name of referenced type, then the OData.nHibernate cannot find the mapping. With the new dictionary the mapping can be found. */ typeIsMapped = _context.SessionFactoryContext.MappedClassMetadata.ContainsKey(type); baseTypeIsMapped = _context.SessionFactoryContext.BaseClassToMappedClass.ContainsKey(type); if (type != null && (typeIsMapped || baseTypeIsMapped) && !isLastMember) { if (typeIsMapped) { mappedClass = _context.SessionFactoryContext.MappedClassMetadata[type]; } else if (baseTypeIsMapped) { mappedClass = _context.SessionFactoryContext.MappedClassMetadata[_context.SessionFactoryContext.BaseClassToMappedClass[type]]; } string path = (lastAliasName != null ? lastAliasName + "." : null) + sb; Alias alias; if (!Aliases.TryGetValue(path, out alias)) { alias = new Alias(_context.CreateUniqueAliasName(), path, type); Aliases.Add(path, alias); _context.AddAlias(alias); } lastAliasName = alias.Name; sb.Clear(); } } return(new ResolvedMemberExpression( expression.MemberType, (lastAliasName != null ? lastAliasName + "." : null) + sb, type )); }
private ICriterion CreateAnyOrAllCriterion(CollectionMethod method, ResolvedMemberExpression resolvedMember, LambdaExpression lambdaExpression) { Require.That(method.MethodType == MethodType.Any || method.MethodType == MethodType.All, "Invalid method type", "method"); // Resolved member's name may contain multiple dots if it's inside a component (i.e. 'root.Component.Collection') int p = resolvedMember.Member.IndexOf('.'); if (p == -1) { throw new ODataException(string.Format("Member '{0}' must have an alias.", resolvedMember.Member)); } var collectionHolderAliasName = resolvedMember.Member.Substring(0, p); var collectionMemberName = resolvedMember.Member.Substring(p + 1); Alias collectionHolderAlias; _context.AliasesByName.TryGetValue(collectionHolderAliasName, out collectionHolderAlias); if (collectionHolderAlias == null) { throw new ODataException(string.Format("Unknown alias '{0}'.", collectionHolderAliasName)); } var subCriteriaAlias = _context.CreateUniqueAliasName(); var detachedCriteria = DetachedCriteria.For(collectionHolderAlias.ReturnedType, subCriteriaAlias); MappedClassMetadata metadata; _context.SessionFactoryContext.MappedClassMetadata.TryGetValue(collectionHolderAlias.ReturnedType, out metadata); if (metadata == null) { throw new ODataException(string.Format("The type '{0}' isn't a NHibernate-mapped class.", collectionHolderAlias.ReturnedType.FullName)); } if (metadata.IdentifierPropertyName == null) { throw new ODataException(string.Format("The type '{0}' doesn't have an identifier property.", collectionHolderAlias.ReturnedType.FullName)); } detachedCriteria.Add(Restrictions.EqProperty( subCriteriaAlias + "." + metadata.IdentifierPropertyName, collectionHolderAliasName + "." + metadata.IdentifierPropertyName )); var lambdaAlias = _context.CreateUniqueAliasName(); System.Type itemType; if (resolvedMember.ReturnedType == null || (itemType = TypeUtil.TryGetCollectionItemType(resolvedMember.ReturnedType)) == null) { throw new ODataException("Cannot get collection item type"); } _context.AddAlias(new Alias(lambdaAlias, string.Empty, itemType)); // The inner joined alias to collection items must be created in any case (whether the lambda expression is specified or not) detachedCriteria.CreateAlias(subCriteriaAlias + "." + collectionMemberName, lambdaAlias, JoinType.InnerJoin); detachedCriteria.SetProjection(Projections.Constant(1)); if (lambdaExpression != null) { if (method.MethodType == MethodType.All) { lambdaExpression = (LambdaExpression)InverseVisitor.Invert(lambdaExpression); } _context.PushLambdaContext(lambdaExpression.ParameterName, itemType, lambdaAlias); try { var lambdaNormalizeVisitor = new AliasingNormalizeVisitor( _context, collectionHolderAlias.ReturnedType, collectionHolderAliasName ); var bodyExpression = lambdaExpression.Body.Visit(lambdaNormalizeVisitor); var criterion = bodyExpression.Visit(new CriterionVisitor(_context)); if (criterion != null) { detachedCriteria.Add(criterion); foreach (var alias in lambdaNormalizeVisitor.Aliases.Values) { detachedCriteria.CreateAlias(alias.AssociationPath, alias.Name, JoinType.LeftOuterJoin); } } } finally { _context.PopLambdaContext(); } } if (method.MethodType == MethodType.Any) { return(Subqueries.Exists(detachedCriteria)); } else { return(Subqueries.NotExists(detachedCriteria)); } }
public override Expression MemberExpression(MemberExpression expression) { var type = _persistentClass; MappedClassMetadata mappedClass = null; var members = expression.Members; var lastAliasName = _rootAlias; // If we are inside a lambda expression if (_context.ExpressionLevel > 1) { // Lambda member expression MUST start with a variable name var lambdaContext = _context.FindLambdaContext(members[0].Name); if (lambdaContext == null) { throw new QueryException(ErrorMessages.Expression_LambdaMemberMustStartWithParameter); } type = lambdaContext.ParameterType; lastAliasName = lambdaContext.ParameterAlias; members = members.Skip(1).ToList(); } else if (members[0].Name == "$it") { // Special case: $it variable outside of lambda expression members = members.Skip(1).ToList(); } if (type != null) { _context.SessionFactoryContext.MappedClassMetadata.TryGetValue(type, out mappedClass); } if (members.Count == 1) { Debug.Assert(members[0].IdExpression == null); string resolvedName = ResolveName(mappedClass, string.Empty, members[0].Name, ref type); return(new ResolvedMemberExpression( expression.MemberType, (lastAliasName != null ? lastAliasName + "." : null) + resolvedName, type )); } var sb = new StringBuilder(); for (int i = 0; i < members.Count; i++) { var member = members[i]; Debug.Assert(member.IdExpression == null); bool isLastMember = i == members.Count - 1; string resolvedName = ResolveName(mappedClass, sb.ToString(), member.Name, ref type); if (sb.Length > 0) { sb.Append('.'); } sb.Append(resolvedName); if (type != null && _context.SessionFactoryContext.MappedClassMetadata.ContainsKey(type) && !isLastMember) { mappedClass = _context.SessionFactoryContext.MappedClassMetadata[type]; string path = (lastAliasName != null ? lastAliasName + "." : null) + sb; Alias alias; if (!Aliases.TryGetValue(path, out alias)) { alias = new Alias(_context.CreateUniqueAliasName(), path, type); Aliases.Add(path, alias); _context.AddAlias(alias); } lastAliasName = alias.Name; sb.Clear(); } } return(new ResolvedMemberExpression( expression.MemberType, (lastAliasName != null ? lastAliasName + "." : null) + sb, type )); }