private static QueryModelReference ComputeDerivedDataReference( MethodCallExpression methodCall, QueryModelReference source) { var method = methodCall.Method; // Source is a sequence of T and output is also a sequence of T var sourceType = method.GetParameters()[0] .ParameterType.FindGenericType(typeof(IEnumerable <>)); var resultType = method.ReturnType .FindGenericType(typeof(IEnumerable <>)); if (sourceType == resultType) { return(new DerivedDataReference(source)); } // Source is a sequence of T and output is a single T var sourceElementType = sourceType.GetGenericArguments()[0]; if (method.ReturnType == sourceElementType) { return(new CollectionElementReference(source)); } // TODO GitHubIssue#29 : Handle projection operators in query expression return(null); }
/// <summary> /// Initializes a new instance of the <see cref="PropertyModelReference" /> class. /// </summary> /// <param name="source"> /// A source query model reference. /// </param> /// <param name="propertyName"> /// The name of a property. /// </param> internal PropertyModelReference(QueryModelReference source, string propertyName) { Ensure.NotNull(propertyName, nameof(propertyName)); this.propertyName = propertyName; Ensure.NotNull(source, nameof(source)); Source = source; }
private QueryModelReference ComputeParameterModelReference(ParameterExpression parameter) { QueryModelReference modelReference = null; foreach (var node in this.GetExpressionTrail()) { var methodCall = node as MethodCallExpression; if (methodCall == null) { continue; } modelReference = this.GetModelReferenceForNode(node); if (modelReference == null) { continue; } var method = methodCall.Method; var sourceType = method.GetParameters()[0].ParameterType.FindGenericType(typeof(IEnumerable <>)); var resultType = method.ReturnType.FindGenericType(typeof(IEnumerable <>)); if (sourceType != resultType) { // In case sourceType IEnumerable<Person> and resultType is // IEnumerable <SelectExpandBinder.SelectAllAndExpand<Person>> // or IEnumerable<SelectExpandBinder.SelectAll<Person>> // or IEnumerable<SelectExpandBinder.SelectSome<Person>> // or IEnumerable<SelectExpandBinder.SelectSomeAndInheritance<Person>> if (sourceType == null || resultType == null) { continue; } var resultGenericType = resultType.GenericTypeArguments[0]; if (!resultGenericType.IsGenericType || resultGenericType.GenericTypeArguments[0] != sourceType.GenericTypeArguments[0]) { continue; } } var typeOfT = sourceType.GenericTypeArguments[0]; if (parameter.Type == typeOfT) { var collectionType = modelReference.Type as IEdmCollectionType; if (collectionType != null) { modelReference = new ParameterModelReference( modelReference.EntitySet, collectionType.ElementType.Definition); return(modelReference); } } } return(modelReference); }
/// <summary> /// Initializes a new instance of the <see cref="PropertyModelReference" /> class. /// </summary> /// <param name="propertyName"> /// The name of a property. /// </param> /// <param name="property"> /// EDM property instance /// </param> /// <param name="source"> /// A source query model reference. /// </param> internal PropertyModelReference(string propertyName, IEdmProperty property, QueryModelReference source) { Ensure.NotNull(propertyName, "propertyName"); this.propertyName = propertyName; Ensure.NotNull(property, "property"); this.property = property; this.Source = source; }
/// <summary> /// Initializes a new instance of the <see cref="PropertyModelReference" /> class. /// </summary> /// <param name="propertyName"> /// The name of a property. /// </param> /// <param name="property"> /// EDM property instance /// </param> /// <param name="source"> /// A source query model reference. /// </param> internal PropertyModelReference(string propertyName, IEdmProperty property, QueryModelReference source) { Ensure.NotNull(propertyName, nameof(propertyName)); this.propertyName = propertyName; Ensure.NotNull(property, nameof(property)); this.property = property; Source = source; }
/// <summary> /// Gets a reference to the model element /// that represents an expression node. /// </summary> /// <param name="node"> /// An expression node. /// </param> /// <returns> /// A reference to the model element /// that represents the expression node. /// </returns> public QueryModelReference GetModelReferenceForNode(Expression node) { QueryModelReference modelReference = null; if (node != null) { this.modelReferences.TryGetValue(node, out modelReference); } return(modelReference); }
private QueryModelReference ComputeMemberModelReference(MemberExpression member) { QueryModelReference modelReference = null; var memberExp = member.Expression; if (memberExp == null) { throw new Exception(string.Format(Resources.QueryMemberNotAccessible, member.ToString())); } if (memberExp.NodeType == ExpressionType.Parameter) { modelReference = GetModelReferenceForNode(memberExp); } else if (memberExp.NodeType == ExpressionType.TypeAs) { var resultType = memberExp.Type; var parameterExpression = (memberExp as UnaryExpression).Operand; // Handle result is employee, and get person's property case // member expression will be "Param_0 As Person" if (parameterExpression.Type.IsSubclassOf(resultType)) { modelReference = GetModelReferenceForNode(parameterExpression); } else { // member expression will be "Param_0 As Employee" var emdEntityType = QueryContext.Model.FindDeclaredType(resultType.FullName); if (emdEntityType is IEdmStructuredType structuredType) { var property = structuredType.FindProperty(member.Member.Name); modelReference = GetModelReferenceForNode(parameterExpression); modelReference = new PropertyModelReference(modelReference, member.Member.Name, property); return(modelReference); } } } if (modelReference != null) { modelReference = new PropertyModelReference(modelReference, member.Member.Name); } return(modelReference); }
private QueryModelReference ComputeMemberModelReference(MemberExpression member) { QueryModelReference modelReference = null; var memberExp = member.Expression; if (memberExp.NodeType == ExpressionType.Parameter) { modelReference = this.GetModelReferenceForNode(memberExp); } else if (memberExp.NodeType == ExpressionType.TypeAs) { var resultType = memberExp.Type; var parameterExpression = (memberExp as UnaryExpression).Operand; // Handle result is employee, and get person's property case // member expression will be "Param_0 As Person" if (parameterExpression.Type.IsSubclassOf(resultType)) { modelReference = this.GetModelReferenceForNode(parameterExpression); } else { // member expression will be "Param_0 As Employee" var emdEntityType = this.QueryContext.Model.FindDeclaredType(resultType.FullName); var structuredType = emdEntityType as IEdmStructuredType; if (structuredType != null) { var property = structuredType.FindProperty(member.Member.Name); modelReference = this.GetModelReferenceForNode(parameterExpression); modelReference = new PropertyModelReference(member.Member.Name, property, modelReference); return(modelReference); } } } if (modelReference != null) { modelReference = new PropertyModelReference( modelReference, member.Member.Name); } return(modelReference); }
private QueryModelReference ComputeModelReference() { QueryModelReference modelReference = null; var methodCall = this.VisitedNode as MethodCallExpression; if (methodCall != null) { var method = methodCall.Method; if (method.DeclaringType == typeof(DataSourceStub) && method.Name != MethodNameOfDataSourceStubValue) { modelReference = ComputeDataSourceStubReference(methodCall); } else if (method.GetCustomAttributes <ExtensionAttribute>().Any()) { var thisModelReference = this.GetModelReferenceForNode(methodCall.Arguments[0]); if (thisModelReference != null) { var model = this.QueryContext.Model; modelReference = ComputeQueryModelReference(methodCall, thisModelReference, model); } } return(modelReference); } var parameter = this.VisitedNode as ParameterExpression; if (parameter != null) { return(ComputeParameterModelReference(parameter)); } var member = this.VisitedNode as MemberExpression; if (member != null) { return(ComputeMemberModelReference(member)); } return(null); }
/// <summary> /// Initializes a new instance of the <see cref="DerivedDataReference" /> class. /// </summary> /// <param name="source"> /// A source query model reference. /// </param> public DerivedDataReference(QueryModelReference source) { Ensure.NotNull(source, "source"); this.Source = source; }
/// <summary> /// Initializes a new instance of the <see cref="CollectionElementReference" /> class. /// </summary> /// <param name="source"> /// A source query model reference. /// </param> public CollectionElementReference(QueryModelReference source) : base(source) { }
/// <summary> /// This method is called by method call like Where/OfType/SelectMany and so on /// to create a model reference for whole function call. /// </summary> /// <param name="methodCall"> /// An method call expression node. /// </param> /// <param name="source"> /// The parameter model reference. /// </param> /// <param name="model"> /// The edm model. /// </param> /// <returns> /// A reference to the model element /// that represents the expression node. /// </returns> private static QueryModelReference ComputeQueryModelReference( MethodCallExpression methodCall, QueryModelReference source, IEdmModel model) { var method = methodCall.Method; // source is a sequence of T and output is also a sequence of T var sourceType = method.GetParameters()[0].ParameterType.FindGenericType(typeof(IEnumerable <>)); var resultType = method.ReturnType.FindGenericType(typeof(IEnumerable <>)); if (sourceType == resultType) { return(new QueryModelReference(source.EntitySet, source.Type)); } Type resultElementType = null; if (resultType != null) { resultElementType = resultType.GenericTypeArguments[0]; } // In case sourceType IEnumerable<Person> and resultType is // IEnumerable <SelectExpandBinder.SelectAllAndExpand<Person>> // or IEnumerable<SelectExpandBinder.SelectAll<Person>> // or IEnumerable<SelectExpandBinder.SelectSome<Person>> // or IEnumerable<SelectExpandBinder.SelectSomeAndInheritance<Person>> if (sourceType != null && resultType != null) { var resultGenericType = resultElementType; if (resultGenericType.IsGenericType) { var resultFinalElementType = resultGenericType.GenericTypeArguments[0]; var sourceElementType = sourceType.GenericTypeArguments[0]; // Handle source is type of sub class and result is a base class if (resultFinalElementType.IsAssignableFrom(sourceElementType)) { return(new QueryModelReference(source.EntitySet, source.Type)); } } } // In this case, the sourceType is null if (method.Name.Equals(MethodNameOfType)) { // Did not consider multiple namespaces have same entity type case or customized namespace var edmEntityType = model.FindDeclaredType(resultElementType.FullName); var collectionType = new EdmCollectionType( new EdmEntityTypeReference((IEdmEntityType)edmEntityType, false)); return(new QueryModelReference(source.EntitySet, collectionType)); } // Till here, it means the result is not part of previous result and entity set will be null // This mean result is a collection as resultType is IEnumerable<> if (resultType != null) { // Did not consider multiple namespaces have same entity type case or customized namespace var edmElementType = model.FindDeclaredType(resultElementType.FullName); // This means result is collection of Entity/Complex/Enum IEdmTypeReference edmTypeReference = null; if (edmElementType != null) { var edmType = edmElementType as IEdmType; edmTypeReference = edmType.GetTypeReference(); if (edmTypeReference != null) { var collectionType = new EdmCollectionType(edmTypeReference); return(new QueryModelReference(null, collectionType)); } } // TODO Here means a collection of primitive type } // TODO Need to handle single result case // TODO GitHubIssue#29 : Handle projection operators in query expression return(null); }
/// <summary> /// Initializes a new instance of the <see cref="PropertyDataReference" /> class. /// </summary> /// <param name="source"> /// A source query model reference. /// </param> /// <param name="propertyName"> /// The name of a property. /// </param> public PropertyDataReference(QueryModelReference source, string propertyName) : base(source) { Ensure.NotNull(propertyName, "propertyName"); this.propertyName = propertyName; }
/// <summary> /// This method is called by method call like Where/OfType/SelectMany and so on /// to create a model reference for whole function call. /// </summary> /// <param name="methodCall"> /// An method call expression node. /// </param> /// <param name="source"> /// The parameter model reference. /// </param> /// <param name="model"> /// The edm model. /// </param> /// <returns> /// A reference to the model element /// that represents the expression node. /// </returns> private static QueryModelReference ComputeQueryModelReference( MethodCallExpression methodCall, QueryModelReference source, IEdmModel model) { var method = methodCall.Method; // source is a sequence of T and output is also a sequence of T var sourceType = method.GetParameters()[0].ParameterType.FindGenericType(typeof(IEnumerable<>)); var resultType = method.ReturnType.FindGenericType(typeof(IEnumerable<>)); if (sourceType == resultType) { return new QueryModelReference(source.EntitySet, source.Type); } Type resultElementType = null; if (resultType != null) { resultElementType = resultType.GenericTypeArguments[0]; } // In case sourceType IEnumerable<Person> and resultType is // IEnumerable <SelectExpandBinder.SelectAllAndExpand<Person>> // or IEnumerable<SelectExpandBinder.SelectAll<Person>> // or IEnumerable<SelectExpandBinder.SelectSome<Person>> // or IEnumerable<SelectExpandBinder.SelectSomeAndInheritance<Person>> if (sourceType != null && resultType != null) { var resultGenericType = resultElementType; if (resultGenericType.IsGenericType) { var resultFinalElementType = resultGenericType.GenericTypeArguments[0]; var sourceElementType = sourceType.GenericTypeArguments[0]; // Handle source is type of sub class and result is a base class if (resultFinalElementType.IsAssignableFrom(sourceElementType)) { return new QueryModelReference(source.EntitySet, source.Type); } } } // In this case, the sourceType is null if (method.Name.Equals(MethodNameOfType)) { // Did not consider multiple namespaces have same entity type case or customized namespace var edmEntityType = model.FindDeclaredType(resultElementType.FullName); var collectionType = new EdmCollectionType( new EdmEntityTypeReference((IEdmEntityType)edmEntityType, false)); return new QueryModelReference(source.EntitySet, collectionType); } // Till here, it means the result is not part of previous result and entity set will be null // This mean result is a collection as resultType is IEnumerable<> if (resultType != null) { // Did not consider multiple namespaces have same entity type case or customized namespace var edmElementType = model.FindDeclaredType(resultElementType.FullName); // This means result is collection of Entity/Complex/Enum IEdmTypeReference edmTypeReference = null; if (edmElementType != null) { var edmType = edmElementType as IEdmType; edmTypeReference = edmType.GetTypeReference(); if (edmTypeReference != null) { var collectionType = new EdmCollectionType(edmTypeReference); return new QueryModelReference(null, collectionType); } } // TODO Here means a collection of primitive type } // TODO Need to handle single result case // TODO GitHubIssue#29 : Handle projection operators in query expression return null; }
private QueryModelReference ComputeModelReference() { QueryModelReference modelReference = null; var methodCall = this.VisitedNode as MethodCallExpression; if (methodCall != null) { var method = methodCall.Method; if (method.DeclaringType == typeof(ApiData) && method.Name != MethodNameOfApiDataValue) { modelReference = ComputeApiDataReference(methodCall); } else if (method.GetCustomAttributes <ExtensionAttribute>().Any()) { var thisModelReference = this.GetModelReferenceForNode( methodCall.Arguments[0]); if (thisModelReference != null) { modelReference = ComputeDerivedDataReference( methodCall, thisModelReference); } } } var parameter = this.VisitedNode as ParameterExpression; if (parameter != null) { foreach (var node in this.GetExpressionTrail()) { methodCall = node as MethodCallExpression; if (methodCall != null) { modelReference = this.GetModelReferenceForNode(node); if (modelReference != null) { var method = methodCall.Method; var sourceType = method.GetParameters()[0] .ParameterType.FindGenericType(typeof(IEnumerable <>)); var resultType = method.ReturnType .FindGenericType(typeof(IEnumerable <>)); if (sourceType == resultType) { var typeOfT = sourceType.GetGenericArguments()[0]; if (parameter.Type == typeOfT) { modelReference = new CollectionElementReference(modelReference); break; } } } } } } var member = this.VisitedNode as MemberExpression; if (member != null) { modelReference = this.GetModelReferenceForNode(member.Expression); if (modelReference != null) { modelReference = new PropertyDataReference( modelReference, member.Member.Name); } } return(modelReference); }
/// <summary> /// Initializes a new instance of the <see cref="PropertyModelReference" /> class. /// </summary> /// <param name="source"> /// A source query model reference. /// </param> /// <param name="propertyName"> /// The name of a property. /// </param> internal PropertyModelReference(QueryModelReference source, string propertyName) { Ensure.NotNull(propertyName, "propertyName"); this.propertyName = propertyName; Ensure.NotNull(source, "source"); this.Source = source; }
private static QueryModelReference ComputeDerivedDataReference( MethodCallExpression methodCall, QueryModelReference source) { var method = methodCall.Method; // Source is a sequence of T and output is also a sequence of T var sourceType = method.GetParameters()[0] .ParameterType.FindGenericType(typeof(IEnumerable<>)); var resultType = method.ReturnType .FindGenericType(typeof(IEnumerable<>)); if (sourceType == resultType) { return new DerivedDataReference(source); } // Source is a sequence of T and output is a single T var sourceElementType = sourceType.GetGenericArguments()[0]; if (method.ReturnType == sourceElementType) { return new CollectionElementReference(source); } // TODO GitHubIssue#29 : Handle projection operators in query expression return null; }
/// <summary> /// Initializes a new instance of the <see cref="PropertyModelReference" /> class. /// </summary> /// <param name="propertyName"> /// The name of a property. /// </param> /// <param name="property"> /// EDM property instance /// </param> /// <param name="source"> /// A source query model reference. /// </param> internal PropertyModelReference(QueryModelReference source, string propertyName, IEdmProperty property) : this(source, propertyName) { Ensure.NotNull(property, nameof(property)); this.property = property; }