/// <summary> /// Get an IQueryable in the extended type given the base type, sourcing data without fetching /// non-summarised fields /// </summary> /// <param name="tBase">The base type</param> /// <returns>IQueryable in extended type which doesn't fetch non-summarised fields</returns> public IQueryable SummarisedSet(Type tBase) { var extender = LyniconSystem.Instance.Extender; if (!extender.BaseTypes.Contains(tBase)) { throw new Exception("No composite of base type " + tBase.FullName); } // Below hack required because constructing the 'project' query (which is .Select(..) under the covers) // causes a database connection to be made, so this must be avoided. The result of the IQueryable returned // is not relevant as it will be ignored, however the item type IS used in TotalCache. if (Repository.Instance.AvoidConnection) { Type itemType = extender[tBase] ?? tBase; Type listType = typeof(List <>).MakeGenericType(itemType); return(((IEnumerable)(Activator.CreateInstance(listType))).AsQueryable()); } Type sumsType = extender.Summarised(tBase); IQueryable q = (IQueryable)ReflectionX.InvokeGenericMethod(this, "SummarisedSet", sumsType); var project = projectors[tBase]; var selectMi = selectors[tBase]; var qryOut = (IQueryable)selectMi.Invoke(null, new object[] { q, project }); return(qryOut); }
public override Func <IQueryable <T>, IQueryable <T> > Apply <T>() { if (keySet == null) { Type summType = ContentTypeHierarchy.SummaryTypes[this.refType]; ReflectionX.InvokeGenericMethod(this, "SetKeySet", false, mi => true, new List <Type> { this.refType, summType }); } // encodes x => x.Prop var xParam = Expression.Parameter(typeof(T), "x"); var accessProp = Expression.MakeMemberAccess(xParam, this.PropInfo); var selector = Expression.Lambda(accessProp, xParam); Type propType = this.PropInfo.PropertyType; Dictionary <Type, TypeConverter> converters = this.keySet.Select(k => k.GetType()).Distinct().ToDictionary(t => t, t => TypeDescriptor.GetConverter(t)); this.keySet = this.keySet.Select(k => k.GetType() == propType ? k : converters[k.GetType()].ConvertTo(k, propType)).ToList(); // if foreign key field was nullable return(iq => iq.WhereIn(selector, this.keySet, propType)); }
/// <summary> /// Get containers by query /// </summary> /// <typeparam name="T">The type of the resulting containers</typeparam> /// <param name="targetType">The content type or summary type of the intended output</param> /// <param name="types">The allowed types of contained content items returned</param> /// <param name="queryBody">An operator on an IQueryable of the container type to filter the ones to return</param> /// <returns>Resulting list of containers</returns> public virtual IEnumerable <T> Get <T>(Type targetType, IEnumerable <Type> types, Func <IQueryable <T>, IQueryable <T> > queryBody) where T : class { if (types == null || !types.Any()) { yield break; } if (types.Count() == 1) { var contentType = types.Single(); var itemEnum = (IEnumerable)ReflectionX.InvokeGenericMethod(this, "BasicGet", new Type[] { contentType, typeof(T) }, targetType, queryBody); foreach (object res in itemEnum) { yield return(res as T); } } else { foreach (Type t in types) { foreach (var res in this.Get <T>(targetType, new Type[] { t }, queryBody)) { yield return(res); } } } }
/// <summary> /// Get containers by addresses /// </summary> /// <param name="targetType">type of contained items these will produce - either 'object' or a summary type</param> /// <param name="addresses">list of addresses to fetch</param> /// <returns>container(s) at addresses</returns> public IEnumerable <object> Get(Type targetType, IEnumerable <Address> addresses) { foreach (var addressG in addresses.GroupBy(ad => ad.Type)) { Type contT = System.Collator.ContainerType(addressG.Key); var pathPiInfo = contT.GetProperties() .Select(pi => new { pi, a = pi.GetCustomAttribute <AddressComponentAttribute>() }) .FirstOrDefault(pii => pii.a != null && pii.a.UsePath); if (pathPiInfo != null) // container has a single property in which the path is stored - we can get all using same repository in one query { foreach (object res in (IEnumerable)ReflectionX.InvokeGenericMethod(this, "Get", mi => { var parms = mi.GetParameters(); return(parms.Length == 2 && parms[1].Name == "addresses"); }, new Type[] { contT }, targetType, addressG)) { yield return(res); } } else // we have to use a query for each item as the path is spread across multiple fields { foreach (Address a in addressG) { var results = (IEnumerable)ReflectionX.InvokeGenericMethod(this, "Get", m => m.GetParameters()[1].ParameterType == typeof(Address), new Type[] { contT }, a.Type, a); foreach (var res in results) { yield return(res); } } } } }
/// <inheritdoc/> public override IEnumerable <T> Get <T>(IEnumerable <Address> addresses) { foreach (var ag in addresses.GroupBy(a => a.Type)) { var typeResults = (IEnumerable <T>)ReflectionX.InvokeGenericMethod(this, "GetAddressesOfType", false, mi => true, new Type[] { typeof(T), ag.Key }, ag); foreach (var res in typeResults) { yield return(res); } } }
/// <inheritdoc/> public override IEnumerable <T> Get <T>(IEnumerable <ItemId> ids) { foreach (var idg in ids.GroupBy(id => id.Type)) { var typeResults = (IEnumerable <T>)ReflectionX.InvokeGenericMethod(this, "GetIdsOfType", false, mi => true, new Type[] { typeof(T), idg.Key }, idg); foreach (var res in typeResults) { yield return(res); } } }
public IActionResult ScanReferences() { List <string> errors = new List <string>(); foreach (Type t in ContentTypeHierarchy.AllContentTypes) { List <string> refErrors = (List <string>)ReflectionX.InvokeGenericMethod(this, "GetReferenceErrors", t); errors.AddRange(refErrors); } return(PartialView(errors)); }
/// <summary> /// Get markup to show all the items of a type in a paged box on the List page /// </summary> /// <param name="datatype">The data type</param> /// <returns>Markup of the paged box listing the items</returns> public ActionResult GetPage(string datatype) { ViewData.Add("UrlPermission", LyniconSecurityManager.Current.CurrentUserInRole(Lynicon.Membership.User.EditorRole)); ViewData.Add("DelPermission", LyniconSecurityManager.Current.CurrentUserInRole(Lynicon.Membership.User.AdminRole)); Type type = ContentTypeHierarchy.GetContentType(datatype); Type containerType = Collator.Instance.ContainerType(type); // invoke Collator.Instance.GetList<Summary, type>(new Type[] { type }, RouteData).ToArray(); var summs = (IEnumerable <Summary>)ReflectionX.InvokeGenericMethod(Collator.Instance, "GetList", new Type[] { typeof(Summary), containerType }, new Type[] { type }, RouteData); var data = summs.ToArray(); return(PartialView("ItemPage", data)); }
/// <summary> /// Get a DbQuery (in the extended type) for a given base type /// </summary> /// <param name="tBase">The base type</param> /// <param name="useIncludes">Whether to use includes specified by AlwaysIncludesAttribute</param> /// <returns>A DbQuery against the underlying database</returns> public IQueryable CompositeSet(Type tBase, bool useIncludes) { var extender = LyniconSystem.Instance.Extender; var ext = extender[tBase]; if (ext == null) { throw new Exception("No composite of base type " + tBase.FullName); } IQueryable q = (IQueryable)ReflectionX.InvokeGenericMethod(this, "InnerCompositeSet", ext, true, useIncludes); return(q); }
/// <summary> /// Get containers by ids /// </summary> /// <typeparam name="T">The type of the resulting containers</typeparam> /// <param name="targetType">The content type or summary type of the intended output</param> /// <param name="ids">The ItemIds of the containers to fetch</param> /// <returns></returns> public virtual IEnumerable <T> Get <T>(Type targetType, IEnumerable <ItemId> ids) where T : class { bool isSummary = typeof(Summary).IsAssignableFrom(targetType); TContext db = GetDb(); try { foreach (var idg in ids.GroupBy(ii => ii.Type)) { if (idg.Count() > MaximumIdBatchSize) { throw new ArgumentException("Request for too many ids at once, request in batches of maximum size " + MaximumIdBatchSize); } var qed = new QueryEventData <IQueryable> { QueryBody = (Func <IQueryable, IQueryable>)ReflectionX.InvokeGenericMethod(this, "GetIdsQuery", idg.Key, idg.Select(ii => ii.Id)) }; qed.Source = ApplyIncludes(idg.Key, ((TContext)db).Set(idg.Key)); qed.Ids = ids; qed = EventHub.Instance.ProcessEvent(isSummary ? "Repository.Get.Summaries.Ids" : "Repository.Get.Items.Ids", this, qed).Data as QueryEventData <IQueryable>; if (qed.EnumSource != null) { foreach (var res in qed.EnumSource) { yield return(res as T); } } else { foreach (var res in qed.QueryBody(qed.Source).AsFacade <T>()) { yield return(res); } } } } finally { if (!isSummary) { EndCallDb((TContext)db); } } }
/// <summary> /// Get a data item, or list of items, via the route which maps to them /// </summary> /// <typeparam name="T">type of the item(s), a generic list if a list of items, could be a summary type</typeparam> /// <param name="contentType">the content type of the item(s)</param> /// <param name="rd">route data</param> /// <returns>the mapped items(s)</returns> public T Get <T>(Type contentType, RouteData rd) where T : class { //CodeTimer.MarkTime("Get via route START"); try { if (typeof(T).IsGenericType() && typeof(T).GetGenericTypeDefinition() == typeof(List <>)) { Type elType = typeof(T).GetGenericArguments()[0]; ICollator coll; List <Type> contentTypes; bool isSummary = typeof(Summary).IsAssignableFrom(elType); if (isSummary) { contentTypes = ContentTypeHierarchy.GetSummaryContainers(elType); if (contentTypes.Select(ct => Registered(ct)).Distinct().Count() != 1) { throw new Exception("Content types containing summary type " + elType.FullName + " dont have 1 unique registered collator, requirement for a dataroute with list type"); } coll = Registered(contentTypes.First()); } else { coll = Registered(elType); contentTypes = new List <Type> { elType }; } T itemList = (T)ReflectionX.InvokeGenericMethod(coll, "GetList", new Type[] { elType, isSummary ? elType : ContainerType(elType) }, contentTypes, rd); return(itemList); } else { ICollator coll = Registered(contentType); return(coll.Get <T>(new List <Address> { coll.GetAddress(contentType, rd) }).FirstOrDefault()); } } finally { //CodeTimer.MarkTime("Get via route END"); } }
/// <summary> /// Get total count of items of a given type in api /// </summary> /// <param name="targetType">type type of item to count</param> /// <returns>count</returns> public int GetCount(Type targetType) { Type type = targetType; if (Registered(targetType) is ContentRepository) { type = typeof(ContentItem); } Type iqType = typeof(IQueryable <>).MakeGenericType(type); ParameterExpression iqParam = Expression.Parameter(iqType, "iq"); LambdaExpression queryExp = Expression.Lambda(iqParam, iqParam); return((int)ReflectionX.InvokeGenericMethod(this, "GetCount", type, new Type[] { targetType }, queryExp.Compile())); }
public override Func <IQueryable <T>, IQueryable <T> > Apply <T>() { if (keySet == null) { Type summType = ContentTypeHierarchy.SummaryTypes[this.refType]; ReflectionX.InvokeGenericMethod(this, "SetKeySet", false, mi => true, new List <Type> { this.refType, summType }); } // encodes x => x.Prop var xParam = Expression.Parameter(typeof(T), "x"); var accessProp = Expression.MakeMemberAccess(xParam, this.PropInfo); var selector = Expression.Lambda(accessProp, xParam); Type propType = this.PropInfo.PropertyType; // if foreign key field was nullable return(iq => iq.WhereIn(selector, this.keySet, propType)); }
/// <summary> /// Get containers by ids /// </summary> /// <typeparam name="T">The type of the resulting containers</typeparam> /// <param name="targetType">The content type or summary type of the intended output</param> /// <param name="ids">The ItemIds of the containers to fetch</param> /// <returns></returns> public IEnumerable <T> Get <T>(Type targetType, IEnumerable <ItemId> ids) where T : class { bool isSummary = typeof(Summary).IsAssignableFrom(targetType); using (var dataSource = DataSourceFactory.Create(isSummary)) { foreach (var idg in ids.GroupBy(ii => ii.Type)) { if (idg.Count() > MaximumIdBatchSize) { throw new ArgumentException("Request for too many ids at once, request in batches of maximum size " + MaximumIdBatchSize); } var qed = new QueryEventData <IQueryable> { QueryBody = (Func <IQueryable, IQueryable>)ReflectionX.InvokeGenericMethod(this, "GetIdsQuery", idg.Key, idg.Select(ii => ii.Id)), Source = dataSource.GetSource(idg.Key), Ids = ids }; qed = EventHub.Instance.ProcessEvent(isSummary ? "Repository.Get.Summaries.Ids" : "Repository.Get.Items.Ids", this, qed).Data as QueryEventData <IQueryable>; if (qed.EnumSource != null) { foreach (var res in qed.EnumSource) { yield return(res as T); } } else { foreach (var res in qed.QueryBody(qed.Source).AsFacade <T>()) { yield return(res); } } } } }
/// <summary> /// Apply a sort to a result row list based on the settings in this FieldFilter /// </summary> /// <param name="source">The result row list</param> /// <returns>The sorted result row list</returns> public override IEnumerable <Tuple <object, Summary> > ApplySort(IEnumerable <Tuple <object, Summary> > source) { return((IEnumerable <Tuple <object, Summary> >)ReflectionX.InvokeGenericMethod(this, "ApplySort", false, mi => true, new Type[] { PropInfo.PropertyType }, source)); }
/// <summary> /// Get a list of container x summary tuples where the content is one of the a list of content types, filtered by container and /// summary filters /// </summary> /// <param name="contentTypes">The allowed content types</param> /// <param name="containerFilters">The filters operating on containers</param> /// <param name="summaryFilters">The filters operating on summaries</param> /// <returns></returns> public List <Tuple <object, Summary> > GetFilterSummaries(List <Type> contentTypes, List <ListFilter> containerFilters, List <ListFilter> summaryFilters) { // Containers var showContFields = new List <PropertyInfo>(); Type containerType = typeof(object); // find most general common type of all ApplicableTypes of filters. If none exists, return empty list. foreach (var filt in containerFilters.Where(f => f.Active)) { if (containerType.IsAssignableFrom(filt.ApplicableType)) { containerType = filt.ApplicableType; } else { return(new List <Tuple <object, Summary> >()); } } if (contentTypes == null || contentTypes.Count == 0) { contentTypes = ContentTypeHierarchy.AllContentTypes.ToList(); } else { contentTypes = contentTypes .SelectMany(t => ContentTypeHierarchy.ContentSubtypes.ContainsKey(t) ? ContentTypeHierarchy.ContentSubtypes[t].Concat(t) : new List <Type> { t }) .Distinct() .ToList(); } // content types must be contained within container type contentTypes = contentTypes.Where(ct => containerType.IsAssignableFrom(Collator.Instance.ContainerType(ct))).ToList(); if (contentTypes.Count == 0) { return(new List <Tuple <object, Summary> >()); } var containers = ((IEnumerable <object>)ReflectionX.InvokeGenericMethod(this, "GetFilteredContainers", containerType, contentTypes, containerFilters.Where(f => f.Active).ToList())); // Summaries var showFields = new List <PropertyInfo>(); Type summaryType = typeof(Summary); foreach (var filt in summaryFilters) { if (summaryType.IsAssignableFrom(filt.ApplicableType)) { summaryType = filt.ApplicableType; } else { return(new List <Tuple <object, Summary> >()); } } var results = (List <Tuple <object, Summary> >)ReflectionX.InvokeGenericMethod(this, "FilterContainers", summaryType, containers, summaryFilters.Where(f => f.Active).ToList()); var orderFilter = containerFilters.FirstOrDefault(cf => cf.Sort != 0); if (orderFilter == null) { orderFilter = summaryFilters.FirstOrDefault(sf => sf.Sort != 0); } if (orderFilter != null) { results = orderFilter.ApplySort(results).ToList(); } return(results); }
/// <summary> /// Get new item whose data address is given by a specified route /// </summary> /// <param name="type">type of new item</param> /// <param name="rd">the specified route</param> /// <returns>the new item</returns> public object GetNew(Type type, RouteData rd) { return(ReflectionX.InvokeGenericMethod(this, "GetNew", mi => mi.GetParameters().First().ParameterType == typeof(RouteData), new Type[] { type }, rd)); }
/// <summary> /// Get some summaries by their ids /// </summary> /// <param name="returnType">type of items returned by repository</param> /// <param name="summaryType">type of summary these will produce</param> /// <param name="targetType">the type of which these are summaries</param> /// <param name="ids">ids of items</param> /// <returns>summary details of items in containers</returns> public IEnumerable <object> Get(Type returnType, Type summaryType, Type targetType, IEnumerable <object> ids) { return((IEnumerable <object>)ReflectionX.InvokeGenericMethod(this, "Get", mi => mi.GetParameters()[2].ParameterType == typeof(IEnumerable <object>), new Type[] { returnType }, summaryType, targetType, ids)); }
/// <summary> /// Get new item whose address is given /// </summary> /// <param name="a">the address to create it at</param> /// <returns>the new item</returns> public object GetNew(Address a) { return(ReflectionX.InvokeGenericMethod(this, "GetNew", mi => mi.GetParameters().First().ParameterType == typeof(Address) && mi.GetGenericArguments().Length == 1, new Type[] { a.Type }, a)); }
/// <summary> /// Get an item's summary by id /// </summary> /// <param name="returnType">type returned by repository</param> /// <param name="summaryType">type of summary this will produce</param> /// <param name="targetType">the type of which this is a summary</param> /// <param name="id">id of item</param> /// <returns>summary details of item in a container</returns> public object Get(Type returnType, Type summaryType, Type targetType, object id) { return(ReflectionX.InvokeGenericMethod(this, "Get", returnType, summaryType, targetType, id)); }