AutoDataModel.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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.Entities.Where(x => x.HasInterface(typeof(IOneToMany<>)) || x.HasInterface(typeof(IManyToMany<,>))).ToArray();
  44. var maps = _allo2mtypes.Where(x =>
  45. x.GetInterfaceDefinition(typeof(IOneToMany<>))?.GenericTypeArguments[0] == typeof(T)
  46. && !x.HasInterface<ISkipLoad>())
  47. .OrderBy(x => x.EntityName());
  48. var childMethod = GetType().GetMethods().Where(x => string.Equals(x.Name, nameof(AddChildTable)) && x.IsGenericMethod).FirstOrDefault();
  49. var lookupMethod = GetType().GetMethods().Where(x => string.Equals(x.Name, nameof(AddLookupTable)) && x.IsGenericMethod).FirstOrDefault();
  50. foreach (var map in maps)
  51. {
  52. var method = childMethod.MakeGenericMethod(typeof(T), map);
  53. var source = CoreUtils.GetPropertyExpression(typeof(T), "ID", typeof(object));
  54. var prop = map.GetProperties().FirstOrDefault(
  55. x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)) &&
  56. !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute)) &&
  57. x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == typeof(T));
  58. var target = CoreUtils.GetPropertyExpression(map, prop.Name + ".ID", typeof(object));
  59. var cols = Core.Columns.None(map);
  60. var columnList = CoreUtils.GetColumnNames(map,
  61. x => !x.DeclaringType.IsAssignableFrom(map) || x.Name.Split('.', StringSplitOptions.None).First() != prop.Name);
  62. foreach (var col in columnList) cols.Add(col);
  63. cols.Add(prop.Name + ".ID");
  64. children.Add(new Tuple<MethodInfo, Expression, Expression, IColumns, string>(method, source, target, cols,
  65. headName + "_" + TableName(map)));
  66. //method.Invoke(this, new object[] { source, target, null, columns, false, null, headName + "_" + TableName(map) });
  67. //_childtables.Add(new Tuple<Type, String, bool>(map, prop.Name, false));
  68. }
  69. var properties = typeof(T).GetProperties().Where(
  70. x => x.PropertyType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntityLink<>))
  71. && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute)));
  72. foreach (var property in properties)
  73. {
  74. var propType = property.PropertyType;
  75. var otherType = propType.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntityLink<>))
  76. .FirstOrDefault().GenericTypeArguments[0];
  77. if (!typeof(ISkipLoad).IsAssignableFrom(otherType))
  78. {
  79. var method = lookupMethod.MakeGenericMethod(typeof(T), otherType);
  80. var source = CoreUtils.GetPropertyExpression(typeof(T), property.Name + ".ID", typeof(object));
  81. var target = CoreUtils.GetPropertyExpression(otherType, "ID", typeof(object));
  82. var tableNameAttribute = property.GetCustomAttribute<DataModelTableNameAttribute>();
  83. var tableName = tableNameAttribute?.TableName ?? TableName(otherType);
  84. lookups.Add(new Tuple<MethodInfo, Expression, Expression, string>(method, source, target,
  85. headName + "_" + tableName));
  86. //method.Invoke(this, new object[] { source, target, null, null, false, null, headName + "_" + TableName(otherType) });
  87. //_childtables.Add(new Tuple<Type, String, bool>(otherType, property.Name, true));
  88. }
  89. }
  90. var mapsLookup = _allo2mtypes.Where(x => x.GetInterfaceDefinition(typeof(IManyToMany<,>))?.GenericTypeArguments.Contains(typeof(T)) == true)
  91. .OrderBy(x => x.EntityName());
  92. foreach (var map in mapsLookup)
  93. {
  94. var method = childMethod.MakeGenericMethod(typeof(T), map);
  95. var source = CoreUtils.GetPropertyExpression(typeof(T), "ID", typeof(object));
  96. var prop = map.GetProperties().FirstOrDefault(
  97. x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink))
  98. && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute))
  99. && x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == typeof(T));
  100. var target = CoreUtils.GetPropertyExpression(map, prop.Name + ".ID", typeof(object));
  101. var lookupAlias = headName + "_" + TableName(map);
  102. var cols = Core.Columns.None(map);
  103. var columnList = CoreUtils.GetColumnNames(map, x => !x.DeclaringType.IsAssignableFrom(map) || x.Name != prop.Name);
  104. foreach (var col in columnList) cols.Add(col);
  105. cols.Add(prop.Name + ".ID");
  106. manyToManys0.Add(new Tuple<MethodInfo, Expression, Expression, IColumns, string>(method, source, target, cols, lookupAlias));
  107. //method.Invoke(this, new object[] { source, target, null, columns, false, null, lookupAlias });
  108. //_childtables.Add(new Tuple<Type, String, bool>(map, prop.Name, false));
  109. var otherType = map.GetInterfaces().Where(
  110. x => x.IsGenericType
  111. && x.GetGenericTypeDefinition() == typeof(IManyToMany<,>))
  112. .FirstOrDefault().GenericTypeArguments.Where(x => x != typeof(T)).FirstOrDefault();
  113. if (!typeof(ISkipLoad).IsAssignableFrom(otherType))
  114. {
  115. method = lookupMethod.MakeGenericMethod(map, otherType);
  116. prop = map.GetProperties().FirstOrDefault(
  117. x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink))
  118. && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute))
  119. && x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == otherType);
  120. source = CoreUtils.GetPropertyExpression(map, prop.Name + ".ID", typeof(object));
  121. target = CoreUtils.GetPropertyExpression(otherType, "ID", typeof(object));
  122. manyToManys1.Add(new Tuple<MethodInfo, Expression, Expression, string, string>(method, source, target, lookupAlias,
  123. lookupAlias + "_" + TableName(otherType)));
  124. //method.Invoke(this, new object[] { source, target, null, null, false, lookupAlias, lookupAlias + "_" + TableName(otherType) });
  125. //_childtables.Add(new Tuple<Type, String, bool>(map, prop.Name, false));
  126. }
  127. }
  128. }
  129. foreach (var child in children)
  130. child.Item1.Invoke(this, new object?[] { child.Item2, child.Item3, null, child.Item4, false, null, child.Item5 });
  131. foreach (var lookup in lookups)
  132. lookup.Item1.Invoke(this, new object?[] { lookup.Item2, lookup.Item3, null, null, false, null, lookup.Item4 });
  133. foreach (var manyToMany0 in manyToManys0)
  134. manyToMany0.Item1.Invoke(this,
  135. new object?[] { manyToMany0.Item2, manyToMany0.Item3, null, manyToMany0.Item4, false, null, manyToMany0.Item5 });
  136. foreach (var manyToMany1 in manyToManys1)
  137. manyToMany1.Item1.Invoke(this,
  138. new object?[] { manyToMany1.Item2, manyToMany1.Item3, null, null, false, manyToMany1.Item4, manyToMany1.Item5 });
  139. }
  140. public AutoDataModel(Filter<T>? filter): this(filter, null, null) { }
  141. public override string Name => typeof(T).EntityName().Split('.').Last();
  142. }
  143. }