/// <summary> /// Executes the expression. /// </summary> /// <typeparam name="T">The entity type.</typeparam> /// <param name="expression">The expression.</param> /// <returns>Returns the result object.</returns> public T Execute <T>(Expression expression) { var genericType = typeof(T); var isEnumerable = typeof(IEnumerable).IsAssignableFrom(genericType); var entityType = isEnumerable ? genericType.GenericTypeArguments[0] : genericType; var methodCallExpression = expression as MethodCallExpression; if (methodCallExpression != null && methodCallExpression.Method.Name == "Count") { entityType = methodCallExpression.Arguments[0].Type.GenericTypeArguments[0]; } var queryExpressionVisitor = new QueryExpressionVisitor(entityType); queryExpressionVisitor.RootTableAlias = Settings.RootTableAlias; queryExpressionVisitor.ParameterAlias = Settings.ParameterAlias; queryExpressionVisitor.ParameterAliasIndex = Settings.ParameterAliasStartIndex; queryExpressionVisitor.JoinTableAlias = Settings.JoinTableAlias; queryExpressionVisitor.JoinTableAliasIndex = Settings.JoinTableAliasStartIndex; string command; IQuery query; if (methodCallExpression != null && methodCallExpression.Method.Name == "Count") { command = queryExpressionVisitor.ParseCountQueryExpression(expression); query = CreateQuery(command, entityType, queryExpressionVisitor); return(_session.ExecuteScalar <T>(query)); } command = queryExpressionVisitor.ParseQueryExpression(expression); query = CreateQuery(command, entityType, queryExpressionVisitor); var entities = _session.ExecuteQuery(query); foreach (var include in queryExpressionVisitor.Includes) { var propertyInfo = entityType.GetProperty(include); foreach (var entity in entities) { propertyInfo.GetValue(entity); } } if (isEnumerable) { var resultList = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(entityType)); foreach (var entity in entities) { resultList.Add(entity); } return((T)resultList); } if (methodCallExpression != null) { if (methodCallExpression.Method.Name == "First" && entities.Count == 0) { throw new InvalidOperationException("The source sequence is empty"); } if (methodCallExpression.Method.Name == "Single" && (entities.Count == 0 || entities.Count > 1)) { throw new InvalidOperationException(entities.Count == 0 ? "The source sequence is empty" : "The source sequence contains more than one item"); } if (methodCallExpression.Method.Name == "SingleOrDefault" && entities.Count > 1) { throw new InvalidOperationException("The source sequence contains more than one item"); } } return(entities.OfType <T>().FirstOrDefault()); }
protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.Method.Name == "Where" || node.Method.Name == "FirstOrDefault" || node.Method.Name == "First" || node.Method.Name == "Single" || node.Method.Name == "SingleOrDefault") { if (node.Method.Name == "FirstOrDefault" || node.Method.Name == "First") { Limit = 1; } Visit(node.Arguments[0]); if (node.Arguments.Count < 2) { return(node); } if (!_hasWhere) { _hasWhere = true; EmitSql("WHERE "); } else { EmitSql(" AND "); _currentEntityMetadata = _sourceEntityMetadata; } Visit(node.Arguments[1]); return(node); } if (node.Method.Name == "Any" || node.Method.Name == "All" || node.Method.Name == "Count") { if (!(node.Arguments[0] is MemberExpression)) { Visit(node.Arguments[0]); if (node.Arguments.Count == 1) { return(node); } if (!_hasWhere) { _hasWhere = true; EmitSql("WHERE "); } else { EmitSql(" AND "); } Visit(node.Arguments[1]); return(node); } var fieldMetadata = (FieldBaseMetadata)_currentEntityMetadata.Fields.FirstOrDefault(x => x.Name == (node.Arguments[0] as MemberExpression).Member.Name) ?? _currentEntityMetadata.ListFields.FirstOrDefault(x => x.Name == (node.Arguments[0] as MemberExpression).Member.Name); string command = null; IList <TableJoin> joins = null; if (node.Arguments.Count == 2) { _subQueryIndex++; var qev = new QueryExpressionVisitor(EntityMetadataResolver.EntityMetadata.FirstOrDefault(x => x.Name == fieldMetadata.FieldType)) { RootTableAlias = $"{RootTableAlias}{_subQueryIndex}", ParameterAlias = ParameterAlias, ParameterAliasIndex = ParameterAliasIndex, JoinTableAlias = JoinTableAlias, JoinTableAliasIndex = JoinTableAliasIndex }; qev._currentAlias = qev.RootTableAlias; //TODO needs beautify qev.Visit(node.Arguments[1]); ParameterAliasIndex = qev.ParameterAliasIndex; foreach (var queryParameter in qev.Parameters) { Parameters.Add(queryParameter); } command = qev.Command; joins = qev.Joins; } var referenceField = ((ListFieldMetadata)fieldMetadata).ReferenceField; if (node.Method.Name == "Any") { EmitSql(string.IsNullOrWhiteSpace(command) ? $"(SELECT COUNT({RootTableAlias}{_subQueryIndex}.Id) FROM {fieldMetadata.FieldType} {RootTableAlias}{_subQueryIndex} WHERE {RootTableAlias}{_subQueryIndex}.{referenceField} = {_currentAlias}.Id) > 0" : $"{_currentAlias}.Id IN (SELECT {RootTableAlias}{_subQueryIndex}.{referenceField} FROM {fieldMetadata.FieldType} {RootTableAlias}{_subQueryIndex} {string.Join(Environment.NewLine, joins.Select(x => x.ToString()))} WHERE {command} AND {RootTableAlias}{_subQueryIndex}.{referenceField} = {_currentAlias}.Id)"); } else if (node.Method.Name == "Count") { EmitSql(string.IsNullOrWhiteSpace(command) ? $"(SELECT COUNT({RootTableAlias}{_subQueryIndex}.Id) FROM {fieldMetadata.FieldType} {RootTableAlias}{_subQueryIndex} WHERE {RootTableAlias}{_subQueryIndex}.{referenceField} = {_currentAlias}.Id)" : $"(SELECT COUNT({RootTableAlias}{_subQueryIndex}.Id) FROM {fieldMetadata.FieldType} {RootTableAlias}{_subQueryIndex} {string.Join(Environment.NewLine, joins.Select(x => x.ToString()))} WHERE {command} AND {RootTableAlias}{_subQueryIndex}.{referenceField} = {_currentAlias}.Id)"); } else { EmitSql($"(SELECT COUNT({RootTableAlias}{_subQueryIndex}.Id) FROM {fieldMetadata.FieldType} {RootTableAlias}{_subQueryIndex} {string.Join(Environment.NewLine, joins.Select(x => x.ToString()))} WHERE {command} AND {RootTableAlias}{_subQueryIndex}.{referenceField} = {_currentAlias}.Id) = (SELECT COUNT({RootTableAlias}{_subQueryIndex}.Id) FROM {fieldMetadata.FieldType} {RootTableAlias}{_subQueryIndex} {string.Join(Environment.NewLine, joins.Select(x => x.ToString()))} WHERE {RootTableAlias}{_subQueryIndex}.{referenceField} = {_currentAlias}.Id)"); } return(node); } if (node.Method.Name == "OrderBy" || node.Method.Name == "ThenBy") { Visit(node.Arguments[0]); _isOrdering = true; Visit(node.Arguments[1]); _isOrdering = false; EmitOrderBy($"{_currentAlias}.{_orderProperty} asc"); _orderProperty = null; _currentAlias = RootTableAlias; _currentEntityMetadata = _sourceEntityMetadata; return(node); } if (node.Method.Name == "OrderByDescending" || node.Method.Name == "ThenByDescending") { Visit(node.Arguments[0]); _isOrdering = true; Visit(node.Arguments[1]); _isOrdering = false; EmitOrderBy($"{_currentAlias}.{_orderProperty} desc"); _orderProperty = null; _currentAlias = RootTableAlias; _currentEntityMetadata = _sourceEntityMetadata; return(node); } if (node.Method.Name == "StartsWith") { Visit(node.Object); var constantValue = DynamicInvokeExpression(node.Arguments[0]); EmitSql(" LIKE "); Parameters.Add(GetQueryParameter($"@{ParameterAlias}{ParameterAliasIndex++}", $"{constantValue}%", _currentFieldMetadata)); EmitSql(Parameters.Last().Name); _currentAlias = RootTableAlias; return(node); } if (node.Method.Name == "EndsWith") { Visit(node.Object); var constantValue = DynamicInvokeExpression(node.Arguments[0]); EmitSql(" LIKE "); Parameters.Add(GetQueryParameter($"@{ParameterAlias}{ParameterAliasIndex++}", $"%{constantValue}", _currentFieldMetadata)); EmitSql(Parameters.Last().Name); _currentAlias = RootTableAlias; return(node); } if (node.Method.Name == "Contains") { Visit(node.Object); var constantValue = DynamicInvokeExpression(node.Arguments[0]); EmitSql(" LIKE "); Parameters.Add(GetQueryParameter($"@{ParameterAlias}{ParameterAliasIndex++}", $"%{constantValue}%", _currentFieldMetadata)); EmitSql(Parameters.Last().Name); _currentAlias = RootTableAlias; return(node); } if (node.Method.Name == "Include") { Visit(node.Arguments[0]); Includes.Add(GetIncludeMember(node.Arguments[1])); return(node); } if (node.Method.Name == "Take") { Limit = (int)DynamicInvokeExpression(node.Arguments[1]); return(Visit(node.Arguments[0])); } if (node.Method.Name == "Skip") { Offset = (int)DynamicInvokeExpression(node.Arguments[1]); return(Visit(node.Arguments[0])); } if (node.Method.Name == "ChangeQueryType") { var entityType = (node.Arguments[1] as ConstantExpression).Value as Type; _currentEntityMetadata = EntityMetadataResolver.GetEntityMetadata(entityType); _sourceEntityMetadata = _currentEntityMetadata; ChangedEntityType = entityType; return(Visit(node.Arguments[0])); } if (node.Method.Name == "Cast") { return(Visit(node.Arguments[0])); } throw new NotSupportedException($"{node.Method.Name} is not supported."); }
private IQuery CreateQuery(string command, Type entityType, QueryExpressionVisitor queryExpressionVisitor) { return(new Query(command, queryExpressionVisitor.ChangedEntityType ?? entityType, queryExpressionVisitor.Parameters)); }