From 3a0af04b1c9953079e65b8a7b8b3d0937c9603c4 Mon Sep 17 00:00:00 2001 From: Railz Date: Tue, 9 Jul 2019 19:42:03 +0200 Subject: [PATCH] Added DbIntermediateForeignObject and resolver Set version to 1.5.20 --- .../Attributes/DbIntermediateForeignObject.cs | 80 +++++++++++++++++++ .../Attributes/DbObject.cs | 6 ++ Database-Attribute_System/ClassAction.cs | 57 ++++++++++++- .../Database-Attribute_System.csproj | 2 +- 4 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 Database-Attribute_System/Attributes/DbIntermediateForeignObject.cs diff --git a/Database-Attribute_System/Attributes/DbIntermediateForeignObject.cs b/Database-Attribute_System/Attributes/DbIntermediateForeignObject.cs new file mode 100644 index 0000000..c069052 --- /dev/null +++ b/Database-Attribute_System/Attributes/DbIntermediateForeignObject.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes +{ + [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] + public class DbIntermediateForeignObject : Attribute + { + public Type foreignObjectType; + + public string _intermediateTableName; + + public string _keyName; + public string _foreignKeyName; + + + public DbPrimaryKey foreignPrimaryKeyAttribute; + + public FieldInfo parentField; + public DbObject classAttribute; + + /// + /// Marks variable as intermediate-object of an dbObject + /// + /// Table-name of intermediate-table. Must contain primaryKey of this class & target class + /// Fieldname of primaryKey associated with the IntermediateObject on this side [m]:n (null if same as primary key) [Only works with 1 primaryKey] + /// Fieldname of primaryKey associated with the IntermediateObject on the other side m:[n] (null if same as primary key) [Only works with 1 primaryKey] + public DbIntermediateForeignObject(string intermediateTableName, string keyName = null, string foreignKeyName = null) + { + this._intermediateTableName = intermediateTableName; + this._foreignKeyName = foreignKeyName; + } + + public void Init(FieldInfo fi, DbObject classAttribute) + { + this.parentField = fi; + this.classAttribute = classAttribute; + this.foreignObjectType = fi.FieldType; + + // Init foreign-object class + DbObject foreignClassAttribute = ClassAction.Init(this.foreignObjectType); + + if (classAttribute.primaryKeyAttributes.Count < 1) throw new InvalidOperationException($"'{classAttribute.parentClassType.Name}' does not have a primaryKey."); + if (classAttribute.primaryKeyAttributes.Count > 1) throw new InvalidOperationException($"IntermediateObject does not support multiple primaryKeys."); + // Get primaryKey name if none is set + if (_keyName == null) _keyName = classAttribute.primaryKeyAttributes[0]._attributeName; + + if (!(fi.FieldType is IList && fi.FieldType.IsGenericType)) // 1:m + throw new InvalidOperationException($"IntermediateObject has to be typeof(List). Maybe you meant to use DbForeignObject or DbReverseForeignObject for 1:m or 1:1 relations."); + + // Check the generic list and get inner-type + Type foreignObjectType = null; + foreach (Type interfaceType in fi.FieldType.GetInterfaces()) + { + if (interfaceType.IsGenericType && + interfaceType.GetGenericTypeDefinition() + == typeof(IList<>)) + { + foreignObjectType = fi.FieldType.GetGenericArguments()[0]; + break; + } + } + if (foreignObjectType == null) throw new InvalidOperationException("Could not read innter-type of generic-list!"); + + // Now get the primaryKey from my foreignObject + DbObject foreignDbObject = ClassAction.Init(foreignObjectType); + // Check the primaryKey/s + if (foreignDbObject.primaryKeyAttributes.Count < 1) throw new InvalidOperationException($"'{foreignDbObject.parentClassType.Name}' does not have a primaryKey."); + if (foreignDbObject.primaryKeyAttributes.Count > 1) throw new InvalidOperationException($"IntermediateObject does not support multiple primaryKeys. (Found '{foreignDbObject.primaryKeyAttributes.Count}' in '{foreignDbObject.parentClassType.Name}')"); + // Save it + foreignPrimaryKeyAttribute = foreignDbObject.primaryKeyAttributes[0]; + + if (_foreignKeyName == null) _foreignKeyName = foreignPrimaryKeyAttribute._attributeName; + } + } +} diff --git a/Database-Attribute_System/Attributes/DbObject.cs b/Database-Attribute_System/Attributes/DbObject.cs index 9adfb74..4f33908 100644 --- a/Database-Attribute_System/Attributes/DbObject.cs +++ b/Database-Attribute_System/Attributes/DbObject.cs @@ -21,6 +21,7 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes public List foreignKeyAttributes = new List() { }; public List foreignObjectAttributes = new List() { }; public List reverseForeignObjectAttributes = new List() { }; + public List intermediateObjectAttributes = new List() { }; /// /// Marks variable as database-table @@ -74,6 +75,11 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes rfobj.Init(fi, this); this.reverseForeignObjectAttributes.Add(rfobj); } + else if (fi.GetCustomAttribute(typeof(DbIntermediateForeignObject), true) is DbIntermediateForeignObject iobj) // ReverseForeignObjects + { + iobj.Init(fi, this); + this.intermediateObjectAttributes.Add(iobj); + } } catch(InvalidOperationException ex) { diff --git a/Database-Attribute_System/ClassAction.cs b/Database-Attribute_System/ClassAction.cs index b882196..d943356 100644 --- a/Database-Attribute_System/ClassAction.cs +++ b/Database-Attribute_System/ClassAction.cs @@ -278,7 +278,6 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System DbObject dbObject = ClassAction.Init(classType); // Resolve foreignObjects - foreach (DbForeignObject foreignObjectAtt in dbObject.foreignObjectAttributes) { object foreignObject_value = foreignObjectAtt.parentField.GetValue(classObject); @@ -322,6 +321,62 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System } } + // Resolve intermediateForeignObjects + foreach (DbIntermediateForeignObject intermediateForeignObjectAtt in dbObject.intermediateObjectAttributes) + { + object intermediateForeignObject_value = intermediateForeignObjectAtt.parentField.GetValue(classObject); + + // When its empty, get it & set it + if (intermediateForeignObject_value == null) + { + // Generate & set attribute-set + Dictionary attributes = new Dictionary(); + attributes.Add(intermediateForeignObjectAtt._keyName, dbObject.primaryKeyAttributes[0].parentField.GetValue(classObject)); + + string query = QueryBuilder.SelectByAttribute(intermediateForeignObjectAtt._intermediateTableName, attributes); // Generate query + List> dataSet = queryExecutor(query); // Execute + // Extract data + List values = new List(); + for (int i=0; i data = dataSet[i]; + object primaryKeyValue = data[intermediateForeignObjectAtt.foreignPrimaryKeyAttribute._attributeName]; + + values.Add(GetByPrimaryKey(intermediateForeignObjectAtt.foreignPrimaryKeyAttribute.classAttribute.parentClassType, primaryKeyValue, queryExecutor)); + } + + // Now scan the just resolved class to be able to set myself + DbObject foreignDbObject = Init(intermediateForeignObjectAtt.foreignPrimaryKeyAttribute.classAttribute.parentClassType); + foreach (DbForeignObject dbForeignObject in foreignDbObject.foreignObjectAttributes) + { + // If the field-names match + if (dbForeignObject._foreignKeyName.ToLower() == dbObject.primaryKeyAttributes[0]._attributeName.ToLower()) + { + object myReference = classObject; + foreach (object value in values) + { + dbForeignObject.parentField.SetValue(value, myReference); + } + break; + } + } + + // Set value + intermediateForeignObject_value = values; + intermediateForeignObjectAtt.parentField.SetValue(classObject, intermediateForeignObject_value); + } + + // Recursive resolving + if (max_depth > 1) + { + // If we have a list of objects, we need to recursively go into each one + foreach (object value in (IList)intermediateForeignObject_value) + { + ResolveForeignKeys(value, queryExecutor, max_depth - 1); + } + } + } + // Resolve reverseForeignObjects foreach (DbReverseForeignObject reverseForeignObjectAtt in dbObject.reverseForeignObjectAttributes) { diff --git a/Database-Attribute_System/Database-Attribute_System.csproj b/Database-Attribute_System/Database-Attribute_System.csproj index 0af05b1..7d5a15a 100644 --- a/Database-Attribute_System/Database-Attribute_System.csproj +++ b/Database-Attribute_System/Database-Attribute_System.csproj @@ -4,7 +4,7 @@ netcoreapp2.1 eu.railduction.netcore.dll.Database_Attribute_System false - 1.5.15 + 1.5.20