AutoDataModel.cs 11 KB

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