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));
        }
Exemple #9
0
        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);
        }
Exemple #10
0
 private Expression GetResultInitExpression(IDictionary <MemberInfo, Expression> memberInitis)
 {
     return(GetInitExpression(ResultType, memberInitis, p => PropertyConfigurations.FirstOrDefault(x => x.PropertyInfo == p)?.Property?.Default));
 }