protected override void ValidateFinal() { base.ValidateFinal(); ExceptionHelper.InvalidOperation.ThrowIfTrue( PropertyConfigurations.Single(prop => prop.IsPrimaryResourceIdentifier).ValueComputationFunc == null, $"The primary identifier for {typeof(TResource).Name} must have a unique value computation function defined for it (e.g. () => Guid.NewGuid())"); }
/// <summary> /// Creates concrete <see cref="BehaviorChain"/>s from the <see /// cref="BehaviorChainConfiguration"/>s and assigns them to the <paramref /// name="descriptor"/> and its VM properties. /// </summary> internal void ApplyTo(IVMDescriptor descriptor) { var chain = ViewModelConfiguration.CreateChain(); chain.Initialize(descriptor); descriptor.Behaviors = chain; PropertyConfigurations.ApplyToProperties(descriptor); }
/// <summary> /// Carry out final validation after all the property configurations (default, convention, user) have been applied. /// </summary> protected virtual void ValidateFinal() { IEnumerable <TPropertyConfiguration> primaryIdentifiers = PropertyConfigurations.Where(prop => prop.IsPrimaryResourceIdentifier); ExceptionHelper.InvalidOperation.ThrowIfTrue( primaryIdentifiers.Count() != 1, $"There must be exactly of 1 property marked as the primary identifier for {typeof(TResource).Name}. " + $"Currently: {string.Join(", ", primaryIdentifiers.Select(x => x.PropertyName))}"); ExceptionHelper.InvalidOperation.ThrowIfTrue( primaryIdentifiers.First().HasComputedValue&& primaryIdentifiers.First().ValueComputationFunc.EndpointTriggers.HasFlag(HttpVerbs.PUT), $"The primary identifier for {typeof(TResource).Name} must not be updatable via PUT."); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual PropertyConfiguration GetOrAddPropertyConfiguration( [NotNull] EntityConfiguration entityConfiguration, [NotNull] Property property) { Check.NotNull(entityConfiguration, nameof(entityConfiguration)); Check.NotNull(property, nameof(property)); var propertyConfiguration = FindPropertyConfiguration(property); if (propertyConfiguration == null) { propertyConfiguration = new PropertyConfiguration(entityConfiguration, property); PropertyConfigurations.Add(propertyConfiguration); } return(propertyConfiguration); }
/// <summary> /// Set any values for the property configurations by conventions. This is called before the user-defined and after the default configuration is applied. /// </summary> protected virtual void SetConventionsForProperties() { var resourceIdName = typeof(TResource).Name.ToLowerInvariant() + "id"; var resourceIdPropertyConfig = PropertyConfigurations.FirstOrDefault(prop => prop.PropertyName.ToLower() == resourceIdName); var idPropertyConfig = PropertyConfigurations.FirstOrDefault(prop => prop.PropertyName.ToLower() == "id"); if (idPropertyConfig != null) { // Set column called Id to primary identifier CreatePropertyConfigurationBuilder <TResource>(idPropertyConfig).IsPrimaryIdentifier(); } else if (resourceIdPropertyConfig != null) { // Set column called [resource_type_name]Id to primary identifier (i.e. Person -> PersonId) CreatePropertyConfigurationBuilder <TResource>(resourceIdPropertyConfig).IsPrimaryIdentifier(); } }
protected override void SetConventionsForProperties() { base.SetConventionsForProperties(); var primaryKey = PropertyConfigurations.FirstOrDefault(x => x.IsPrimaryResourceIdentifier); if (primaryKey?.PropertyType == typeof(int)) { CreatePropertyConfigurationBuilder <int>(primaryKey).HasComputedValue(HttpVerbs.POST).AutoIncrementingInteger(); } else if (primaryKey?.PropertyType == typeof(Guid)) { CreatePropertyConfigurationBuilder <Guid>(primaryKey).HasComputedValue(HttpVerbs.POST).RandomlyGeneratedGuid(); } else if (primaryKey?.PropertyType == typeof(int?)) { CreatePropertyConfigurationBuilder <int?>(primaryKey).HasComputedValue(HttpVerbs.POST).AutoIncrementingInteger(); } else if (primaryKey?.PropertyType == typeof(Guid?)) { CreatePropertyConfigurationBuilder <Guid?>(primaryKey).HasComputedValue(HttpVerbs.POST).RandomlyGeneratedGuid(); } }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual List <PropertyConfiguration> GetPropertyConfigurations(bool useFluentApiOnly) { return(PropertyConfigurations .Where(pc => pc.GetFluentApiConfigurations(useFluentApiOnly).Any()).ToList()); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public virtual PropertyConfiguration FindPropertyConfiguration([NotNull] IProperty property) { Check.NotNull(property, nameof(property)); return(PropertyConfigurations.FirstOrDefault(pc => pc.Property == property)); }
public virtual IQueryable GetQuery(QuerySource source, QueryConfiguration config) { var propsToQuery = PropertyConfigurations.ToList(); if (config.Select.Any()) { var columns = config.Select.ToList(); var filterPaths = config.TargetFilterItems.SelectMany(p => p.GetValueExpressions()).OfType <PathValueExpression>().Select(p => p.Path).ToList(); var fromSortAndFilter = config.Sort.Select(p => p.PropertyPath).Concat(filterPaths) .Select(p => p.Split('.').First()).Distinct().ToList(); foreach (var missing in fromSortAndFilter.Where(p => !columns.Any(x => x.Property == p)).ToList()) { columns.Add(new SelectItem(missing)); } propsToQuery = (from p in PropertyConfigurations join c in columns on p.Property.Name equals c.Property select p).ToList(); } var columnDependencies = propsToQuery.SelectMany(p => p.DependsOn).Distinct().ToList(); var dict = new Dictionary <string, List <string> >(); ResolveDependencies(columnDependencies, dict); var sortedDependencies = new List <string>(); while (dict.Any()) { var items = dict.Where(p => !p.Value.Any()).OrderBy(p => p.Key).Select(p => p.Key).ToList(); if (!items.Any()) { throw new InvalidOperationException("Circular dependency found!"); } sortedDependencies.AddRange(items); foreach (var toRemove in items) { dict.Remove(toRemove); foreach (var item in dict) { item.Value.Remove(toRemove); } } } var param = Expression.Parameter(this.SourceType, "p"); IQueryable baseQuery = CreateBaseQuery(source, sortedDependencies); var filter = new FilterItemGroup(config.FilterItems); baseQuery = baseQuery.ApplyFilterItem(filter); var members = propsToQuery.ToDictionary(p => (MemberInfo)p.PropertyInfo, p => p.MappedExpression.Body.Replace(p.MappedExpression.Parameters.First(), param)); var initExpression = GetResultInitExpression(members); var selectExpresssion = Expression.Lambda(initExpression, param); var queryExpression = Expression.Call( QueryableInfo.Select.MakeGenericMethod(SourceType, ResultType), baseQuery.Expression, Expression.Quote(selectExpresssion)); baseQuery = baseQuery.Provider.CreateQuery(queryExpression); if (config.TargetFilterItems.Any()) { var targetFilter = new FilterItemGroup(config.TargetFilterItems); baseQuery = baseQuery.ApplyFilterItem(targetFilter); } if (config.Sort.Any()) { baseQuery = baseQuery.ApplySort(config.Sort); } return(baseQuery); }
private Expression GetResultInitExpression(IDictionary <MemberInfo, Expression> memberInitis) { return(GetInitExpression(ResultType, memberInitis, p => PropertyConfigurations.FirstOrDefault(x => x.PropertyInfo == p)?.Property?.Default)); }