AutoDataModel.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. using System.Threading.Tasks;
  7. namespace InABox.Core
  8. {
  9. internal static class _AutoDataModel
  10. {
  11. private static Type[]? _allo2mtypes;
  12. public static Type[] GetOneOrManyToManyTypes()
  13. {
  14. _allo2mtypes ??= CoreUtils.Entities.Where(x => x.HasInterface(typeof(IOneToMany<>)) || x.HasInterface(typeof(IManyToMany<,>))).ToArray();
  15. return _allo2mtypes;
  16. }
  17. }
  18. public class AutoDataModel<T> : DataModel<T> where T : Entity, IPersistent, IRemotable, new()
  19. {
  20. private static bool _loaded = false;
  21. // Method; Parent Column; Child Column; Columns expression; Table Name
  22. private static readonly List<Tuple<MethodInfo, Expression, Expression, IColumns, string>> children =
  23. new List<Tuple<MethodInfo, Expression, Expression, IColumns, string>>();
  24. // Method; Parent Column; Child Column; Table Name
  25. private static readonly List<Tuple<MethodInfo, Expression, Expression, string>> lookups =
  26. new List<Tuple<MethodInfo, Expression, Expression, string>>();
  27. //
  28. private static readonly List<Tuple<MethodInfo, Expression, Expression, IColumns, string>> manyToManys0 =
  29. new List<Tuple<MethodInfo, Expression, Expression, IColumns, string>>();
  30. private static readonly List<Tuple<MethodInfo, Expression, Expression, string, string>> manyToManys1 =
  31. new List<Tuple<MethodInfo, Expression, Expression, string, string>>();
  32. //private List<Tuple<String,Type>> _lookuptables = new List<Tuple<String,Type>>();
  33. private readonly List<Tuple<Type, string, bool>> _childtables = new List<Tuple<Type, string, bool>>();
  34. public AutoDataModel(Filter<T>? filter, Columns<T>? columns, SortOrder<T>? sort) : base(filter, columns, sort)
  35. {
  36. //var props = CoreUtils.PropertyList(typeof(T), x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)));
  37. //foreach (var prop in props)
  38. //{
  39. // var lookuptype = prop.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault();
  40. // if (lookuptype != null)
  41. // {
  42. // MethodInfo method = this.GetType().GetMethod("AddLookupTable").MakeGenericMethod(typeof(T), lookuptype);
  43. // var source = CoreUtils.GetPropertyExpression(typeof(T), prop.Name + ".ID", typeof(object));
  44. // var target = CoreUtils.GetPropertyExpression(lookuptype, "ID", typeof(object));
  45. // method.Invoke(this, new object[] { source, target, false, null, prop.Name });
  46. // _lookuptables.Add(new Tuple<String,Type>(prop.Name,lookuptype));
  47. // }
  48. //}
  49. var headName = TableName<T>();
  50. if (!_loaded)
  51. {
  52. var maps = _AutoDataModel.GetOneOrManyToManyTypes()
  53. .Where(x => x.GetInterfaces(typeof(IOneToMany<>)).Any(x => x.GenericTypeArguments[0] == typeof(T)) && !x.HasInterface<ISkipLoad>())
  54. .OrderBy(x => x.Name);
  55. var childMethod = GetType().GetMethods().Where(x => string.Equals(x.Name, nameof(AddChildTable)) && x.IsGenericMethod).FirstOrDefault();
  56. var lookupMethod = GetType().GetMethods().Where(x => string.Equals(x.Name, nameof(AddLookupTable)) && x.IsGenericMethod).FirstOrDefault();
  57. foreach (var map in maps)
  58. {
  59. var method = childMethod.MakeGenericMethod(typeof(T), map);
  60. var source = CoreUtils.GetPropertyExpression(typeof(T), "ID", typeof(object));
  61. var prop = map.GetProperties().FirstOrDefault(
  62. x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)) &&
  63. !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute)) &&
  64. x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == typeof(T));
  65. var target = CoreUtils.GetPropertyExpression(map, prop.Name + ".ID", typeof(object));
  66. var cols = Core.Columns.None(map);
  67. var columnList = CoreUtils.GetColumnNames(map, x => x.GetOuterParent(x => x.IsEntityLink)?.Name != prop.Name);
  68. foreach (var col in columnList) cols.Add(col);
  69. cols.Add(prop.Name + ".ID");
  70. children.Add(new Tuple<MethodInfo, Expression, Expression, IColumns, string>(method, source, target, cols,
  71. headName + "_" + TableName(map)));
  72. //method.Invoke(this, new object[] { source, target, null, columns, false, null, headName + "_" + TableName(map) });
  73. //_childtables.Add(new Tuple<Type, String, bool>(map, prop.Name, false));
  74. }
  75. var properties = typeof(T).GetProperties().Where(
  76. x => x.PropertyType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntityLink<>))
  77. && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute)));
  78. foreach (var property in properties)
  79. {
  80. var propType = property.PropertyType;
  81. var otherType = propType.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntityLink<>))
  82. .FirstOrDefault().GenericTypeArguments[0];
  83. if (!typeof(ISkipLoad).IsAssignableFrom(otherType))
  84. {
  85. var method = lookupMethod.MakeGenericMethod(typeof(T), otherType);
  86. var source = CoreUtils.GetPropertyExpression(typeof(T), property.Name + ".ID", typeof(object));
  87. var target = CoreUtils.GetPropertyExpression(otherType, "ID", typeof(object));
  88. var tableNameAttribute = property.GetCustomAttribute<DataModelTableNameAttribute>();
  89. var tableName = tableNameAttribute?.TableName ?? TableName(otherType);
  90. lookups.Add(new Tuple<MethodInfo, Expression, Expression, string>(method, source, target,
  91. headName + "_" + tableName));
  92. //method.Invoke(this, new object[] { source, target, null, null, false, null, headName + "_" + TableName(otherType) });
  93. //_childtables.Add(new Tuple<Type, String, bool>(otherType, property.Name, true));
  94. }
  95. }
  96. var mapsLookup = _AutoDataModel.GetOneOrManyToManyTypes()
  97. .Where(x => x.GetInterfaces(typeof(IManyToMany<,>)).Any(x => x.GenericTypeArguments.Contains(typeof(T))))
  98. .OrderBy(x => x.EntityName());
  99. foreach (var map in mapsLookup)
  100. {
  101. var method = childMethod.MakeGenericMethod(typeof(T), map);
  102. var source = CoreUtils.GetPropertyExpression(typeof(T), "ID", typeof(object));
  103. var prop = map.GetProperties().FirstOrDefault(
  104. x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink))
  105. && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute))
  106. && x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == typeof(T));
  107. var target = CoreUtils.GetPropertyExpression(map, prop.Name + ".ID", typeof(object));
  108. var lookupAlias = headName + "_" + TableName(map);
  109. var cols = Core.Columns.None(map);
  110. var columnList = CoreUtils.GetColumnNames(map, x => x.GetOuterParent(x => x.IsEntityLink)?.Name != prop.Name);
  111. foreach (var col in columnList) cols.Add(col);
  112. cols.Add(prop.Name + ".ID");
  113. manyToManys0.Add(new Tuple<MethodInfo, Expression, Expression, IColumns, string>(method, source, target, cols, lookupAlias));
  114. //method.Invoke(this, new object[] { source, target, null, columns, false, null, lookupAlias });
  115. //_childtables.Add(new Tuple<Type, String, bool>(map, prop.Name, false));
  116. var otherType = map.GetInterfaces().Where(
  117. x => x.IsGenericType
  118. && x.GetGenericTypeDefinition() == typeof(IManyToMany<,>))
  119. .FirstOrDefault().GenericTypeArguments.Where(x => x != typeof(T)).FirstOrDefault();
  120. if (!typeof(ISkipLoad).IsAssignableFrom(otherType))
  121. {
  122. method = lookupMethod.MakeGenericMethod(map, otherType);
  123. prop = map.GetProperties().FirstOrDefault(
  124. x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink))
  125. && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute))
  126. && x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == otherType);
  127. source = CoreUtils.GetPropertyExpression(map, prop.Name + ".ID", typeof(object));
  128. target = CoreUtils.GetPropertyExpression(otherType, "ID", typeof(object));
  129. manyToManys1.Add(new Tuple<MethodInfo, Expression, Expression, string, string>(method, source, target, lookupAlias,
  130. lookupAlias + "_" + TableName(otherType)));
  131. //method.Invoke(this, new object[] { source, target, null, null, false, lookupAlias, lookupAlias + "_" + TableName(otherType) });
  132. //_childtables.Add(new Tuple<Type, String, bool>(map, prop.Name, false));
  133. }
  134. }
  135. _loaded = true;
  136. }
  137. foreach (var child in children)
  138. child.Item1.Invoke(this, new object?[] { child.Item2, child.Item3, null, child.Item4, false, null, child.Item5 });
  139. foreach (var lookup in lookups)
  140. lookup.Item1.Invoke(this, new object?[] { lookup.Item2, lookup.Item3, null, null, false, null, lookup.Item4 });
  141. foreach (var manyToMany0 in manyToManys0)
  142. manyToMany0.Item1.Invoke(this,
  143. new object?[] { manyToMany0.Item2, manyToMany0.Item3, null, manyToMany0.Item4, false, null, manyToMany0.Item5 });
  144. foreach (var manyToMany1 in manyToManys1)
  145. manyToMany1.Item1.Invoke(this,
  146. new object?[] { manyToMany1.Item2, manyToMany1.Item3, null, null, false, manyToMany1.Item4, manyToMany1.Item5 });
  147. }
  148. public AutoDataModel(Filter<T>? filter): this(filter, null, null) { }
  149. public override string Name => typeof(T).EntityName().Split('.').Last();
  150. }
  151. }