/// <summary> /// 子类在查询接口方法中,调用此方法来向服务端执行指定的数据层查询方法,并返回满足条件的数据表格。 /// </summary> /// <typeparam name="TRepository">子仓库的类型</typeparam> /// <param name="dataQueryExp">调用子仓库类中定义的数据查询方法的表达式。</param> /// <returns>返回满足条件的数据表格。</returns> protected LiteDataTable FetchTable <TRepository>(Expression <Func <TRepository, LiteDataTable> > dataQueryExp) where TRepository : EntityRepository { var ieqc = new IEQC(); ParseExpToIEQC(dataQueryExp, ieqc); return(DataPortalFetchTable(ieqc)); }
/// <summary> /// 子类在查询接口方法中,调用此方法来向服务端执行指定的数据层查询方法,并返回满足条件的实体列表。 /// </summary> /// <typeparam name="TRepository">子仓库的类型</typeparam> /// <param name="dataQueryExp">调用子仓库类中定义的数据查询方法的表达式。</param> /// <returns>返回满足条件的实体列表。</returns> protected EntityList FetchList <TRepository>(Expression <Func <TRepository, EntityList> > dataQueryExp) where TRepository : EntityRepository { var ieqc = new IEQC(); ParseExpToIEQC(dataQueryExp, ieqc); return(DataPortalFetchList(ieqc)); }
private EntityList DataPortalFetchList(IEQC ieqc) { this.OnFetching(ieqc); var list = DataPortalApi.Fetch(this.GetType(), ieqc, this.DataPortalLocation) as EntityList; this.NotifyLoaded(list); return(list); }
/// <summary> /// 子类在查询接口方法中,调用此方法来导向服务端执行指定的数据层查询方法,并返回统计的行数。 /// </summary> /// <typeparam name="TRepository">子仓库的类型</typeparam> /// <param name="dataQueryExp">调用子仓库类中定义的数据查询方法的表达式。</param> /// <returns>返回统计的行数。</returns> protected int FetchCount <TRepository>(Expression <Func <TRepository, EntityList> > dataQueryExp) where TRepository : EntityRepository { var ieqc = new IEQC { FetchType = FetchType.Count }; ParseExpToIEQC(dataQueryExp, ieqc); return(DataPortalFetchList(ieqc).TotalCount); }
/// <summary> /// 子类在查询接口方法中,调用此方法来导向服务端执行指定的数据层查询方法,并返回第一个满足条件的实体。 /// </summary> /// <typeparam name="TRepository">子仓库的类型</typeparam> /// <param name="dataQueryExp">调用子仓库类中定义的数据查询方法的表达式。</param> /// <returns>返回第一个满足条件的实体。</returns> protected Entity FetchFirst <TRepository>(Expression <Func <TRepository, EntityList> > dataQueryExp) where TRepository : EntityRepository { var ieqc = new IEQC { FetchType = FetchType.First }; ParseExpToIEQC(dataQueryExp, ieqc); var list = DataPortalFetchList(ieqc); return(DisconnectFirst(list)); }
/// <summary> /// 来自数据门户的数据查询 /// </summary> /// <param name="criteria">The criteria.</param> /// <returns></returns> internal object PortalFetch(IEQC criteria) { //如果方法名为空,则使用约定的方法名。 var methodName = criteria.MethodName ?? EntityConvention.GetByCriteriaMethod; var parameters = criteria.Parameters; object result = null; //先尝试在 DataProvider 中调用指定的方法,如果没有找到,才会调用 Repository 中的方法。 if (!MethodCaller.CallMethodIfImplemented( _dataProvider, methodName, parameters, out result )) { result = MethodCaller.CallMethod(this, methodName, parameters); } return(result); }
/// <summary> /// 解析方法调用表达式,获取方法名及参数列表,存入到 IEQC 对象中。 /// </summary> /// <param name="dataQueryExp"></param> /// <param name="ieqc"></param> private void ParseExpToIEQC(LambdaExpression dataQueryExp, IEQC ieqc) { dataQueryExp = Evaluator.PartialEval(dataQueryExp) as LambdaExpression; var methodCallExp = dataQueryExp.Body as MethodCallExpression; if (methodCallExp == null) { ExpressionNotSupported(dataQueryExp); } //repoExp 可以是仓库本身,也可以是 DataProvider,所以以下检测不再需要。 //var repoExp = methodCallExp.Object as ParameterExpression; //if (repoExp == null || !repoExp.Type.IsInstanceOfType(this)) ExpressionNotSupported(dataQueryExp); //参数转换 var arguments = methodCallExp.Arguments; ieqc.Parameters = new object[arguments.Count]; for (int i = 0, c = arguments.Count; i < c; i++) { var argumentExp = arguments[i] as ConstantExpression; if (argumentExp == null) { ExpressionNotSupported(dataQueryExp); } //把参数的值设置到数组中,如果值是 null,则需要使用参数的类型。 ieqc.Parameters[i] = argumentExp.Value ?? new MethodCaller.NullParameter { ParameterType = argumentExp.Type }; } //方法转换 ieqc.MethodName = methodCallExp.Method.Name; }
public void Intercept(IInvocation invocation) { #region 预处理,根据返回值的类型来判断 FetchType。 //if (Attribute.IsDefined(invocation.TargetType, typeof(IgnoreProxyAttribute)) // || Attribute.IsDefined(invocation.Method, typeof(IgnoreProxyAttribute))) //{ // invocation.Proceed(); // return; //} var fetchType = RepositoryQueryType.List; var returnType = invocation.Method.ReturnType; if (returnType.IsClass) { if (typeof(EntityList).IsAssignableFrom(returnType)) { fetchType = RepositoryQueryType.List; } else if (typeof(Entity).IsAssignableFrom(returnType)) { fetchType = RepositoryQueryType.First; } else if (returnType == typeof(LiteDataTable)) { fetchType = RepositoryQueryType.Table; } else { throw new NotSupportedException("仓库查询不支持返回 {0} 类型。".FormatArgs(returnType)); } } else { fetchType = RepositoryQueryType.Count; } #endregion var ieqc = new IEQC { MethodName = invocation.Method.Name, Parameters = invocation.Arguments, QueryType = fetchType }; var repoExt = invocation.InvocationTarget as IRepositoryExt; var repo = invocation.InvocationTarget as EntityRepository ?? repoExt.Repository as EntityRepository; //只是不要纯客户端,都直接使用本地访问 if (repo.DataPortalLocation == DataPortalLocation.Local || RafyEnvironment.Location.ConnectDataDirectly) { using (FinalDataPortal.CurrentQueryCriteriaItem.UseScopeValue(ieqc)) { try { RafyEnvironment.ThreadPortalCount++; if (repoExt != null) { //invoke repositoryExt invocation.Proceed(); } else { //先尝试在 DataProvider 中调用指定的方法,如果没有找到,才会调用 Repository 中的方法。 //这样可以使得 DataProvider 中定义同名方法即可直接重写仓库中的方法。 object result = null; if (MethodCaller.CallMethodIfImplemented( repo.DataProvider, invocation.Method.Name, invocation.Arguments, out result )) { invocation.ReturnValue = result; } else { //invoke repository invocation.Proceed(); } } } finally { RafyEnvironment.ThreadPortalCount--; } } } else { //调用数据门户,使得在服务端才执行真正的数据层方法。 invocation.ReturnValue = DataPortalApi.Fetch(invocation.TargetType, ieqc, repo.DataPortalLocation); } #region Repository.NotifyLoaded switch (fetchType) { case RepositoryQueryType.List: var list = invocation.ReturnValue as EntityList; repo.NotifyLoaded(list); break; case RepositoryQueryType.First: var entity = invocation.ReturnValue as Entity; repo.NotifyLoaded(entity); break; case RepositoryQueryType.Count: case RepositoryQueryType.Table: default: break; } #endregion }