コード例 #1
0
        /// <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());
        }
コード例 #2
0
        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.");
        }
コード例 #3
0
 private IQuery CreateQuery(string command, Type entityType, QueryExpressionVisitor queryExpressionVisitor)
 {
     return(new Query(command, queryExpressionVisitor.ChangedEntityType ?? entityType,
                      queryExpressionVisitor.Parameters));
 }