예제 #1
0
        protected static Entity create(EntityClass parent, entitySpec entitySpec, Type type, Action <string> log, bool throwOnCircularReference)
        {
            log?.Invoke($"create: {type.Name} - {entitySpec.name}");

            if (!string.IsNullOrEmpty(entitySpec.aggregation))
            {
                return(new EntityAggregation(entitySpec, log));
            }
            if (!string.IsNullOrEmpty(entitySpec.formula))
            {
                return(new EntityFormula(entitySpec, log));
            }

            var fieldInfo = new LinkedFieldInfo(type, entitySpec.name);

            if (fieldInfo.IEnumerable != null)
            {
                return(new EntityClass(parent, entitySpec, fieldInfo.IEnumerable.GetGenericArguments()[0], fieldInfo, log, throwOnCircularReference));
            }
            if (!entitySpec.AnyNotStar())
            {
                return(new EntityPlainField(entitySpec, fieldInfo, log));
            }

            throw new Exception("Unknown error");
        }
예제 #2
0
        public EntityPlainField(entitySpec entitySpec, LinkedFieldInfo fieldInfo, Action <string> log)
            : base(entitySpec)
        {
            log?.Invoke($"EntityPlainField ctor: {entitySpec.name}/{entitySpec.fields?.Count ?? 0} - {fieldInfo.FieldType} ");

            FieldInfo = fieldInfo;
            FieldType = FieldInfo.FieldType;
        }
예제 #3
0
        public LinkedFieldInfo(Type type, string name)
        {
            if (name == "@")
            {
                // auto-referencing
                FieldType = type;
                _getValue = _ => _;
            }
            else
            {
                var split = name.Split(".".ToCharArray(), 2);
                _fieldInfo = type.GetField(split[0], BindingFlags.Public | BindingFlags.Instance);
                if (_fieldInfo == null)
                {
                    _propertyInfo = type.GetProperty(split[0], BindingFlags.Public | BindingFlags.Instance);
                    if (_propertyInfo == null)
                    {
                        throw new ArgumentException($"Field or property '{name}' not found in type '{type.Name}'");
                    }
                    if (split.Length > 1)
                    {
                        Next = new LinkedFieldInfo(_propertyInfo.PropertyType, split[1]);
                    }
                }
                else if (split.Length > 1)
                {
                    Next = new LinkedFieldInfo(_fieldInfo.FieldType, split[1]);
                }
                var x = this;
                while (x.Next != null)
                {
                    x = x.Next;
                }
                FieldType = x._fieldInfo?.FieldType ?? x._propertyInfo.PropertyType;

                if (_propertyInfo != null)
                {
                    _getValue = generateFastPropertyFetcher(type, _propertyInfo);
                }
                else if (_fieldInfo != null)
                {
                    _getValue = generateFastFieldFetcher(type, _fieldInfo);
                }
            }

            IEnumerable = CheckForIEnumerable(FieldType);
            Cohersions.TryGetValue(StripNullable(FieldType).Name, out _coherse);
        }
예제 #4
0
 public entitySpec(Entity entity)
 {
     name         = entity.Name;
     externalname = entity.ExternalName != name ? entity.ExternalName : null;
     nosave       = entity.NoSave;
     aggregation  = entity.Spec.aggregation;
     formula      = entity.Spec.formula;
     where        = entity.Spec.where;
     type         = LinkedFieldInfo.FriendlyTypeName(entity.FieldType);
     foreach (var e in entity.Fields)
     {
         Add(new entitySpec(e));
     }
     foreach (var e in entity.Lists)
     {
         Add(new entitySpec(e));
     }
 }
예제 #5
0
        public SqlTable(
            ITableManager tableManager,
            EntityClass entity,
            bool isTopTable,
            bool isLeafTable,
            int primaryKeyIndex,
            int flushThreshold)
        {
            TableManager    = tableManager;
            _flushThreshold = flushThreshold;
            Name            = entity.TableName;
            IsTopTable      = isTopTable;
            IsLeafTable     = isLeafTable;
            PrimaryKeyIndex = primaryKeyIndex;
            Fields          = entity.Fields.Where(_ => !_.NoSave).Select(_ => new NameAndType(_.ExternalName, _.FieldType)).ToList();
            if (Fields.Any(_ => string.IsNullOrEmpty(_.Name)))
            {
                throw new ArgumentException($"Table {Name} contains empty column name");
            }

            _dataTable = new DataTable();
            if (AutomaticPrimaryKey)
            {
                _dataTable.Columns.Add("_id_", typeof(Guid)).AllowDBNull = false;
            }
            if (!IsTopTable)
            {
                ForeignKeyName = entity.ForeignKeyName;
                var dc = _dataTable.Columns.Add(ForeignKeyName, entity.ForeignKeyType);
                if (entity.ForeignKeyType == typeof(string))
                {
                    dc.MaxLength = 100;
                }
                dc.AllowDBNull = false;
            }
            foreach (var field in Fields)
            {
                var dc = _dataTable.Columns.Add(field.Name, LinkedFieldInfo.StripNullable(field.Type));
                dc.AllowDBNull = field.Type == typeof(string) || field.Type == typeof(byte[]) || field.Type != LinkedFieldInfo.StripNullable(field.Type);
            }
        }
예제 #6
0
        public EntityClass(
            EntityClass parent,
            entitySpec entitySpec,
            Type type,
            LinkedFieldInfo fieldInfo,
            Action <string> log,
            bool throwOnCircularReference)
            : base(entitySpec)
        {
            log?.Invoke(
                $"EntityClass ctor: {entitySpec.name}/{entitySpec.fields?.Count ?? 0} - {type?.Name} - {fieldInfo?.FieldType} - {fieldInfo?.IEnumerable?.Name}");

            TableName = parent != null && Spec.externalname == null
                ? string.Join("_", parent.TableName, ExternalName)
                : ExternalName;

            FieldInfo = fieldInfo;
            FieldType = fieldInfo?.FieldType;

            if (!Spec.Any() || isStarExpansionAndNoRealSubProperties(type))
            {
                // not sure if this should be allowed...
                Fields.Add(new EntitySolitaire(type));
            }

            breakDownSubEntities(type, log, throwOnCircularReference);

            // move the nosave fields to always be at the end of the list
            var noSaveFields = Fields.Where(_ => _.NoSave).ToList();

            Fields.RemoveAll(_ => _.NoSave);
            SaveableFieldCount = Fields.Count;
            Fields.AddRange(noSaveFields);

            // this is temporary - to be able to serialze a contract with "*" since it was digging up so much garbage...
            // need to investigae each "garbage" occurrence and handle it more elegantly
            Fields.RemoveAll(_ => _ is EntityPlainField && SqlHelpers.Field2Sql(_.NameAndType.Name, _.NameAndType.Type, false, 0, true) == null);
            Lists.RemoveAll(_ => !_.Fields.Any() && !_.Lists.Any());

            if (Fields.Count(_ => _.Spec.primarykey) > 1)
            {
                throw new Exception("There may be no more than one primary key field");
            }
            PrimaryKeyIndex = Fields.FindIndex(_ => _.Spec.primarykey);

            EffectiveFieldCount = Fields.Count + 1;
            for (var fi = 0; fi < Fields.Count; fi++)
            {
                Fields[fi].ParentInitialized(this, fi);
            }
            for (var li = 0; li < Lists.Count; li++)
            {
                Lists[li].ParentInitialized(this, li);
            }

            for (var i = 0; i < Fields.Count; i++)
            {
                Fields[i].ResultSetIndex = i;
            }

            var fieldsThenFormulas = Fields.Where(_ => !(_ is EntityAggregation)).ToList();

            SortWithFormulasLast(fieldsThenFormulas);
            _fieldsThenNonAggregatedFormulas = fieldsThenFormulas.Where(_ => !_.IsBasedOnAggregation).ToArray();
            _aggregatedFormulas = fieldsThenFormulas.Where(_ => _.IsBasedOnAggregation).ToArray();

            if (!string.IsNullOrEmpty(Spec.where))
            {
                _whereClause = new WhereClause(Spec.where, Fields, _fieldsThenNonAggregatedFormulas);
            }

            if (PrimaryKeyIndex >= 0 && Fields[PrimaryKeyIndex].IsBasedOnAggregation)
            {
                throw new Exception($"The primary key must not be based on an aggregation (table '{TableName}')");
            }
        }
예제 #7
0
        private static IEnumerable <Entity> expansionOverStar(
            Action <string> log,
            EntityClass parent,
            Type masterType,
            entitySpec subEntitySpec,
            HashSet <Type> detectCircularRef,
            bool throwOnCircularReference,
            string prefix = "",
            Type subType  = null)
        {
            if (subEntitySpec.name != "*")
            {
                yield return(create(parent, subEntitySpec, masterType, log, throwOnCircularReference));

                yield break;
            }

            subType = subType ?? masterType;

            if (detectCircularRef.Contains(subType))
            {
                if (throwOnCircularReference)
                {
                    throw new Exception("Circular reference detected while processing inclusion of all fields ('*')");
                }
                else
                {
                    yield return(new EntityClass(parent, entitySpec.Begin(prefix.TrimEnd(".".ToCharArray())), masterType, null, log, true));

                    yield break;
                }
            }
            detectCircularRef.Add(subType);

            foreach (var nameAndType in LinkedFieldInfo.GetAllFieldsAndProperties(subType))
            {
                if (nameAndType.Type == typeof(object))
                {
                    continue;
                }
                var spec          = entitySpec.Begin(prefix + nameAndType.Name);
                var subProperties = LinkedFieldInfo.GetAllFieldsAndProperties(nameAndType.Type);
                if (LinkedFieldInfo.CheckForIEnumerable(nameAndType.Type) != null)
                {
                    spec.Add("*");
                    yield return(create(parent, spec, masterType, log, throwOnCircularReference));
                }
                else if (!subProperties.Any())
                {
                    yield return(create(parent, spec, masterType, log, throwOnCircularReference));
                }

                foreach (var liftedSubProperty in subProperties)
                {
                    if (liftedSubProperty.Type == typeof(object))
                    {
                        continue;
                    }
                    var propName = $"{prefix}{nameAndType.Name}.{liftedSubProperty.Name}";
                    if (LinkedFieldInfo.GetAllFieldsAndProperties(liftedSubProperty.Type).Any())
                    {
                        foreach (var q in expansionOverStar(log, parent, masterType, "*", detectCircularRef, throwOnCircularReference, propName + ".", liftedSubProperty.Type))
                        {
                            yield return(q);
                        }
                    }
                    else
                    {
                        yield return(create(parent, entitySpec.Begin(propName).Add("*"), masterType, log, throwOnCircularReference));
                    }
                    //yield return create(propName, masterType, log);
                }
            }

            detectCircularRef.Remove(subType);
        }
예제 #8
0
 private bool isStarExpansionAndNoRealSubProperties(Type type)
 {
     return(Spec.fields.First().name == "*" && !LinkedFieldInfo.GetAllFieldsAndProperties(type).Any());
 }
예제 #9
0
 public EntitySolitaire(Type type)
     : base(entitySpec.Begin("@", "value"))
 {
     FieldInfo = LinkedFieldInfo.Null(type);
     FieldType = FieldInfo.FieldType;
 }
예제 #10
0
 public object CoherseType(object obj)
 {
     return(FieldInfo != null
         ? FieldInfo.CoherseType(obj)
         : LinkedFieldInfo.CoherseType(FieldType, obj));
 }