/// <summary>
        /// 通过查询表达式来查询实体。
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public object Execute(Expression expression)
        {
            bool forceCounting = false;

            //如果最后调用了 Call 方法,则返回总行数。
            if (expression.NodeType == ExpressionType.Call)
            {
                var call = expression as MethodCallExpression;
                if (call.Method.DeclaringType == typeof(Queryable) && call.Method.Name == LinqConsts.QueryableMethod_Count)
                {
                    if (call.Arguments.Count > 1)
                    {
                        throw EntityQueryBuilder.OperationNotSupported(call.Method);
                    }

                    forceCounting = true;
                    expression    = call.Arguments[0];
                }
            }

            var list = this.QueryEntityList(expression, forceCounting);

            if (forceCounting)
            {
                return(list.TotalCount);
            }
            return(list);
        }
Beispiel #2
0
        protected override Expression VisitMethodCall(MethodCallExpression exp)
        {
            var method = exp.Method;

            _isAny = method.Name == LinqConsts.EnumerableMethod_Any;

            //先访问表达式 book.ChapterList.Cast<Chapter>(),获取列表属性。
            var invoker = exp.Arguments[0];

            _parentPropertyFinder.Find(invoker);
            var listPropertyTable = _parentPropertyFinder.PropertyOwnerTable;
            var listProperty      = _parentPropertyFinder.Property as IListProperty;

            if (listProperty == null)
            {
                throw EntityQueryBuilder.OperationNotSupported(invoker);
            }

            //为该列表对应的实体创建表对象、查询对象。
            var childRepo  = RepositoryFactoryHost.Factory.FindByEntity(listProperty.ListEntityType);
            var childTable = f.Table(childRepo);

            _query = f.Query(
                from: childTable,
                selection: f.Literal("1")
                );
            var qgc = QueryGenerationContext.Get(_parentQuery);

            qgc.Bind(_query);
            childTable.Alias = qgc.NextTableAlias();

            //Any、All 方法如果有第二个参数,那么第二个参数就是条件表达式。如:c => c.Name == chapterName
            if (exp.Arguments.Count == 2)
            {
                var reverseWhere = !_isAny;//如果是 All,则需要反转里面的所有操作符。
                var queryBuilder = new EntityQueryBuilder(childRepo, reverseWhere);
                queryBuilder.BuildQuery(exp.Arguments[1], _query);
            }

            //添加子表查询与父实体的关系条件:WHERE c.BookId = b.Id
            var parentProperty      = childRepo.FindParentPropertyInfo(true);
            var parentRefIdProperty = (parentProperty.ManagedProperty as IRefProperty).RefIdProperty;
            var toParentConstraint  = f.Constraint(childTable.Column(parentRefIdProperty), listPropertyTable.IdColumn);

            _query.Where = f.And(toParentConstraint, _query.Where);

            return(exp);
        }
Beispiel #3
0
        protected override Expression VisitMember(MemberExpression m)
        {
            //只能访问属性
            var clrProperty = m.Member as PropertyInfo;

            if (clrProperty == null)
            {
                throw EntityQueryBuilder.OperationNotSupported(m.Member);
            }
            var ownerExp = m.Expression;

            if (ownerExp == null)
            {
                throw EntityQueryBuilder.OperationNotSupported(m.Member);
            }

            //exp 如果是: A 或者 A.B.C,都可以作为属性查询。
            var nodeType = ownerExp.NodeType;

            if (nodeType != ExpressionType.Parameter && nodeType != ExpressionType.MemberAccess)
            {
                throw EntityQueryBuilder.OperationNotSupported(m.Member);
            }

            //如果是 A.B.C.Name,则先读取 A.B.C,记录最后一个引用实体类型 C;剩下 .Name 给本行后面的代码读取。
            VisitRefEntity(ownerExp);

            //属性的拥有类型对应的仓库。
            //获取当前正在查询的实体对应的仓库对象。如果是级联引用表达式,则使用最后一个实体即可。
            var ownerTable = _query.MainTable;
            var ownerRepo  = _repo;

            if (_lastJoinRefResult != null)
            {
                //如果已经有引用属性在列表中,说明上层使用了 A.B.C.Name 这样的语法。
                //这时,Name 应该是 C 这个实体的值属性。
                ownerRepo          = RepositoryFactoryHost.Factory.FindByEntity(_lastJoinRefResult.RefEntityType);
                ownerTable         = _lastJoinTable;
                _lastJoinRefResult = null;
                _lastJoinTable     = null;
            }

            //查询托管属性
            var mp = EntityQueryBuilder.FindProperty(ownerRepo, clrProperty);

            if (mp == null)
            {
                throw EntityQueryBuilder.OperationNotSupported("Linq 查询的属性必须是一个托管属性。");
            }
            if (mp is IRefEntityProperty)
            {
                //如果是引用属性,说明需要使用关联查询。
                var refProperty = mp as IRefEntityProperty;
                var refTable    = f.FindOrCreateJoinTable(_query, ownerTable, refProperty);

                if (refProperty.Nullable)
                {
                    var column = ownerTable.Column(refProperty.RefIdProperty);
                    NullableRefConstraint = _reverseConstraint ?
                                            f.Or(NullableRefConstraint, column.Equal(null as object)) :
                                            f.And(NullableRefConstraint, column.NotEqual(null as object));
                }

                //存储到字段中,最后的值属性会使用这个引用属性对应的引用实体类型来查找对应仓库。
                _lastJoinRefResult = refProperty;
                _lastJoinTable     = refTable;
                return(m);
            }

            if (_visitRefProperties)
            {
                throw EntityQueryBuilder.OperationNotSupported(string.Format("不支持使用属性:{0}。这是因为它的拥有者是一个值属性,值属性只支持直接对比。", mp.Name));
            }

            //访问值属性
            PropertyOwnerTable = ownerTable;
            Property           = mp;

            return(m);
        }