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"); }
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; }
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); }
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)); } }
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); } }
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}')"); } }
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); }
private bool isStarExpansionAndNoRealSubProperties(Type type) { return(Spec.fields.First().name == "*" && !LinkedFieldInfo.GetAllFieldsAndProperties(type).Any()); }
public EntitySolitaire(Type type) : base(entitySpec.Begin("@", "value")) { FieldInfo = LinkedFieldInfo.Null(type); FieldType = FieldInfo.FieldType; }
public object CoherseType(object obj) { return(FieldInfo != null ? FieldInfo.CoherseType(obj) : LinkedFieldInfo.CoherseType(FieldType, obj)); }