using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; namespace InABox.Core { internal static class _AutoDataModel { private static Type[]? _allo2mtypes; public static Type[] GetOneOrManyToManyTypes() { _allo2mtypes ??= CoreUtils.Entities.Where(x => x.HasInterface(typeof(IOneToMany<>)) || x.HasInterface(typeof(IManyToMany<,>))).ToArray(); return _allo2mtypes; } } public class AutoDataModel : DataModel where T : Entity, IPersistent, IRemotable, new() { private static bool _loaded = false; // Method; Parent Column; Child Column; Columns expression; Table Name private static readonly List> children = new List>(); // Method; Parent Column; Child Column; Table Name private static readonly List> lookups = new List>(); // private static readonly List> manyToManys0 = new List>(); private static readonly List> manyToManys1 = new List>(); //private List> _lookuptables = new List>(); private readonly List> _childtables = new List>(); public AutoDataModel(Filter? filter, Columns? columns, SortOrder? sort) : base(filter, columns, sort) { //var props = CoreUtils.PropertyList(typeof(T), x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink))); //foreach (var prop in props) //{ // var lookuptype = prop.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault(); // if (lookuptype != null) // { // MethodInfo method = this.GetType().GetMethod("AddLookupTable").MakeGenericMethod(typeof(T), lookuptype); // var source = CoreUtils.GetPropertyExpression(typeof(T), prop.Name + ".ID", typeof(object)); // var target = CoreUtils.GetPropertyExpression(lookuptype, "ID", typeof(object)); // method.Invoke(this, new object[] { source, target, false, null, prop.Name }); // _lookuptables.Add(new Tuple(prop.Name,lookuptype)); // } //} var headName = TableName(); if (!_loaded) { var maps = _AutoDataModel.GetOneOrManyToManyTypes() .Where(x => x.GetInterfaces(typeof(IOneToMany<>)).Any(x => x.GenericTypeArguments[0] == typeof(T)) && !x.HasInterface()) .OrderBy(x => x.Name); var childMethod = GetType().GetMethods().Where(x => string.Equals(x.Name, nameof(AddChildTable)) && x.IsGenericMethod).FirstOrDefault(); var lookupMethod = GetType().GetMethods().Where(x => string.Equals(x.Name, nameof(AddLookupTable)) && x.IsGenericMethod).FirstOrDefault(); foreach (var map in maps) { var method = childMethod.MakeGenericMethod(typeof(T), map); var source = CoreUtils.GetPropertyExpression(typeof(T), "ID", typeof(object)); var prop = map.GetProperties().FirstOrDefault( x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)) && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute)) && x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == typeof(T)); var target = CoreUtils.GetPropertyExpression(map, prop.Name + ".ID", typeof(object)); var cols = Core.Columns.None(map); var columnList = CoreUtils.GetColumnNames(map, x => x.GetOuterParent(x => x.IsEntityLink)?.Name != prop.Name); foreach (var col in columnList) cols.Add(col); cols.Add(prop.Name + ".ID"); children.Add(new Tuple(method, source, target, cols, headName + "_" + TableName(map))); //method.Invoke(this, new object[] { source, target, null, columns, false, null, headName + "_" + TableName(map) }); //_childtables.Add(new Tuple(map, prop.Name, false)); } var properties = typeof(T).GetProperties().Where( x => x.PropertyType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntityLink<>)) && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute))); foreach (var property in properties) { var propType = property.PropertyType; var otherType = propType.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEntityLink<>)) .FirstOrDefault().GenericTypeArguments[0]; if (!typeof(ISkipLoad).IsAssignableFrom(otherType)) { var method = lookupMethod.MakeGenericMethod(typeof(T), otherType); var source = CoreUtils.GetPropertyExpression(typeof(T), property.Name + ".ID", typeof(object)); var target = CoreUtils.GetPropertyExpression(otherType, "ID", typeof(object)); var tableNameAttribute = property.GetCustomAttribute(); var tableName = tableNameAttribute?.TableName ?? TableName(otherType); lookups.Add(new Tuple(method, source, target, headName + "_" + tableName)); //method.Invoke(this, new object[] { source, target, null, null, false, null, headName + "_" + TableName(otherType) }); //_childtables.Add(new Tuple(otherType, property.Name, true)); } } var mapsLookup = _AutoDataModel.GetOneOrManyToManyTypes() .Where(x => x.GetInterfaces(typeof(IManyToMany<,>)).Any(x => x.GenericTypeArguments.Contains(typeof(T)))) .OrderBy(x => x.EntityName()); foreach (var map in mapsLookup) { var method = childMethod.MakeGenericMethod(typeof(T), map); var source = CoreUtils.GetPropertyExpression(typeof(T), "ID", typeof(object)); var prop = map.GetProperties().FirstOrDefault( x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)) && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute)) && x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == typeof(T)); var target = CoreUtils.GetPropertyExpression(map, prop.Name + ".ID", typeof(object)); var lookupAlias = headName + "_" + TableName(map); var cols = Core.Columns.None(map); var columnList = CoreUtils.GetColumnNames(map, x => x.GetOuterParent(x => x.IsEntityLink)?.Name != prop.Name); foreach (var col in columnList) cols.Add(col); cols.Add(prop.Name + ".ID"); manyToManys0.Add(new Tuple(method, source, target, cols, lookupAlias)); //method.Invoke(this, new object[] { source, target, null, columns, false, null, lookupAlias }); //_childtables.Add(new Tuple(map, prop.Name, false)); var otherType = map.GetInterfaces().Where( x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IManyToMany<,>)) .FirstOrDefault().GenericTypeArguments.Where(x => x != typeof(T)).FirstOrDefault(); if (!typeof(ISkipLoad).IsAssignableFrom(otherType)) { method = lookupMethod.MakeGenericMethod(map, otherType); prop = map.GetProperties().FirstOrDefault( x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)) && !x.CustomAttributes.Any(y => y.AttributeType == typeof(ObsoleteAttribute)) && x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == otherType); source = CoreUtils.GetPropertyExpression(map, prop.Name + ".ID", typeof(object)); target = CoreUtils.GetPropertyExpression(otherType, "ID", typeof(object)); manyToManys1.Add(new Tuple(method, source, target, lookupAlias, lookupAlias + "_" + TableName(otherType))); //method.Invoke(this, new object[] { source, target, null, null, false, lookupAlias, lookupAlias + "_" + TableName(otherType) }); //_childtables.Add(new Tuple(map, prop.Name, false)); } } _loaded = true; } foreach (var child in children) child.Item1.Invoke(this, new object?[] { child.Item2, child.Item3, null, child.Item4, false, null, child.Item5 }); foreach (var lookup in lookups) lookup.Item1.Invoke(this, new object?[] { lookup.Item2, lookup.Item3, null, null, false, null, lookup.Item4 }); foreach (var manyToMany0 in manyToManys0) manyToMany0.Item1.Invoke(this, new object?[] { manyToMany0.Item2, manyToMany0.Item3, null, manyToMany0.Item4, false, null, manyToMany0.Item5 }); foreach (var manyToMany1 in manyToManys1) manyToMany1.Item1.Invoke(this, new object?[] { manyToMany1.Item2, manyToMany1.Item3, null, null, false, manyToMany1.Item4, manyToMany1.Item5 }); } public AutoDataModel(Filter? filter): this(filter, null, null) { } public override string Name => typeof(T).EntityName().Split('.').Last(); } }