diff --git a/Database-Attribute_System/Attributes/BaseAttribute.cs b/Database-Attribute_System/Attributes/BaseAttribute.cs new file mode 100644 index 0000000..79df0d2 --- /dev/null +++ b/Database-Attribute_System/Attributes/BaseAttribute.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes +{ + public class BaseAttribute : Attribute + { + public FieldInfo parentField; + public DbObject classAttribute; + + public string _attributeName; + + public BaseAttribute() + { + + } + } +} diff --git a/Database-Attribute_System/Attributes/DbAttribute.cs b/Database-Attribute_System/Attributes/BaseAttributes/DbAttribute.cs similarity index 59% rename from Database-Attribute_System/Attributes/DbAttribute.cs rename to Database-Attribute_System/Attributes/BaseAttributes/DbAttribute.cs index b3889c8..e7d67d3 100644 --- a/Database-Attribute_System/Attributes/DbAttribute.cs +++ b/Database-Attribute_System/Attributes/BaseAttributes/DbAttribute.cs @@ -1,22 +1,29 @@ using System; 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 DbAttribute : Attribute + public class DbAttribute : BaseAttribute { - public string _attributeName; - /// /// Marks variable as database-attribute /// /// Name of database-attribute (case-sensitivity is determined from database-attribute-settings) ['null' if the same as field-name] public DbAttribute(string attributeName = null) { - this._attributeName = attributeName; // Todo: Automatic resolving of name if it is null (?) + this._attributeName = attributeName; + } + + public void Init(FieldInfo fi, DbObject classAttribute) + { + this.parentField = fi; + this.classAttribute = classAttribute; + + this._attributeName = this._attributeName ?? fi.Name; // If no alternative attribute-name is specified, use the property-name } } } diff --git a/Database-Attribute_System/Attributes/BaseAttributes/DbForeignKey.cs b/Database-Attribute_System/Attributes/BaseAttributes/DbForeignKey.cs new file mode 100644 index 0000000..b403f7c --- /dev/null +++ b/Database-Attribute_System/Attributes/BaseAttributes/DbForeignKey.cs @@ -0,0 +1,29 @@ +using System; +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 DbForeignKey : BaseAttribute + { + /// + /// Marks variable as foreignKey of given class + /// + /// Name of database-attribute (case-sensitivity is determined from database-attribute-settings) ['null' if the same as field-name] + public DbForeignKey(string attributeName = null) + { + this._attributeName = attributeName; + } + + public void Init(FieldInfo fi, DbObject classAttribute) + { + this.parentField = fi; + this.classAttribute = classAttribute; + + this._attributeName = this._attributeName ?? fi.Name; // If no alternative attribute-name is specified, use the property-name + } + } +} diff --git a/Database-Attribute_System/Attributes/DbPrimaryKey.cs b/Database-Attribute_System/Attributes/BaseAttributes/DbPrimaryKey.cs similarity index 66% rename from Database-Attribute_System/Attributes/DbPrimaryKey.cs rename to Database-Attribute_System/Attributes/BaseAttributes/DbPrimaryKey.cs index ba4b473..c8e8c15 100644 --- a/Database-Attribute_System/Attributes/DbPrimaryKey.cs +++ b/Database-Attribute_System/Attributes/BaseAttributes/DbPrimaryKey.cs @@ -1,16 +1,14 @@ using System; 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 DbPrimaryKey : Attribute + public class DbPrimaryKey : BaseAttribute { - public Type _classType; - public string _attributeName; - /// /// Marks variable as primaryKey fo current class /// @@ -19,5 +17,13 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes { this._attributeName = attributeName; // Todo: Automatic resolving of name if it is null (?) } + + public void Init(FieldInfo fi, DbObject classAttribute) + { + this.parentField = fi; + this.classAttribute = classAttribute; + + this._attributeName = this._attributeName ?? fi.Name; // If no alternative attribute-name is specified, use the property-name + } } } diff --git a/Database-Attribute_System/Attributes/DbForeignKey.cs b/Database-Attribute_System/Attributes/DbForeignKey.cs deleted file mode 100644 index 156daa0..0000000 --- a/Database-Attribute_System/Attributes/DbForeignKey.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -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 DbForeignKey : Attribute - { - public Type _classType; - public string _attributeName; - public string _foreignKeyFieldName; - public FieldInfo _foreignKeyField; - - /// - /// Marks variable as foreignKey of given class - /// - /// Type of class to which this is the ForeignKey - /// Name of database-attribute (case-sensitivity is determined from database-attribute-settings) ['null' if the same as field-name] - /// Name of foreignKey-fieldName ['null' if the same as classType-name] - public DbForeignKey(Type classType, string foreignKeyFieldName = null, string attributeName = null) - { - this._classType = classType; - this._attributeName = attributeName; // Todo: Automatic resolving of name if it is null (?) - - bool fieldFound = false; - foreach (System.Reflection.FieldInfo fi in classType.GetRuntimeFields()) - { - if(fi.Name.ToLower() == foreignKeyFieldName.ToLower()) - { - this._foreignKeyFieldName = fi.Name; - this._foreignKeyField = fi; - - fieldFound = true; - break; - } - } - if (!fieldFound) throw new InvalidOperationException($"Field with name='{foreignKeyFieldName}' not found in {classType.Name}."); - } - } -} diff --git a/Database-Attribute_System/Attributes/DbForeignObject.cs b/Database-Attribute_System/Attributes/DbForeignObject.cs new file mode 100644 index 0000000..5045304 --- /dev/null +++ b/Database-Attribute_System/Attributes/DbForeignObject.cs @@ -0,0 +1,80 @@ +using System; +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 DbForeignObject : Attribute + { + public Type _foreignObjectType; + + public string _foreignKeyName; + public DbForeignKey foreignKeyAttribute; + + public FieldInfo parentField; + public DbObject classAttribute; + + /// + /// Marks variable as foreign-object of an dbObject + /// + /// Type of foreignObject + /// Fieldname of foreignKey associated with the foreignObject + public DbForeignObject(Type foreignObjectType, string foreignKeyName = null) + { + this._foreignObjectType = foreignObjectType; + this._foreignKeyName = foreignKeyName; + } + + public void Init(FieldInfo fi, DbObject classAttribute) + { + this.parentField = fi; + this.classAttribute = classAttribute; + + // Init foreign-object class + DbObject foreignClassAttribute = ClassAction.Init(this._foreignObjectType); + + // Check if something is weird + if (foreignClassAttribute.primaryKeyAttributes.Count < 1) throw new InvalidOperationException($"'{foreignClassAttribute.parentClassType.Name}' does not have a primaryKey."); + if (foreignClassAttribute.primaryKeyAttributes.Count > 1) throw new InvalidOperationException($"ForeignObject does not support multiple primaryKeys."); + + Type primaryKeyType = foreignClassAttribute.primaryKeyAttributes[0].parentField.GetType(); // Read type of primaryKey in foreignObject-class + foreach(DbForeignKey foreignKey in classAttribute.foreignKeyAttributes) // Search for matching foreignKey + { + if(this._foreignKeyName != null) // If i have a name + { + // check if name matches + if (foreignKey.parentField.Name.ToLower() == this._foreignKeyName) + { + if(foreignKey.parentField.GetType() == primaryKeyType) + { + this._foreignKeyName = foreignKey.parentField.Name; + foreignKeyAttribute = foreignKey; + break; + } + else + { + // If a name was specified and the key does not match its an error + throw new InvalidOperationException($"ForeignKey='{this._foreignKeyName}' is typeOf='{foreignKey.parentField.GetType().Name}' but primaryKey of foreignObject-class is typeOf='{primaryKeyType.Name}'."); + } + } + } + else // No name + { + // Check if type matches + if (foreignKey.parentField.GetType() == primaryKeyType) + { + this._foreignKeyName = foreignKey.parentField.Name; + foreignKeyAttribute = foreignKey; + break; + } + } + } + + // Check if key-retrieval was successful + if (foreignKeyAttribute == null) throw new InvalidOperationException($"No coresponding foreignKey."); + } + } +} diff --git a/Database-Attribute_System/Attributes/DbObject.cs b/Database-Attribute_System/Attributes/DbObject.cs index 06eaa4d..3c7807e 100644 --- a/Database-Attribute_System/Attributes/DbObject.cs +++ b/Database-Attribute_System/Attributes/DbObject.cs @@ -12,6 +12,15 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes { public string _tableName; + public Type parentClassType; + + // All childrenAttributes + public List baseAttributes = new List() { }; + public List primaryKeyAttributes = new List() { }; + public List attributeAttributes = new List() { }; + public List foreignKeyAttributes = new List() { }; + public List foreignObjectAttributes = new List() { }; + /// /// Marks variable as database-table /// @@ -20,5 +29,51 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System.Attributes { this._tableName = tableName; // Todo: Automatic resolving of name if it is null (?) } + + public void Init(Type classType) + { + this.parentClassType = classType; + this._tableName = this._tableName ?? classType.Name; // If no alternative table-name is specified, use the class-name + + // Iterate thru all fields + foreach (System.Reflection.FieldInfo fi in classType.GetRuntimeFields()) + { + try + { + // Check if current field is a db-field and initiate it + if (fi.GetCustomAttribute(typeof(DbPrimaryKey), true) is DbPrimaryKey pkey) // PrimaryKey + { + pkey.Init(fi, this); + + this.baseAttributes.Add(pkey); + this.primaryKeyAttributes.Add(pkey); + } + else if (fi.GetCustomAttribute(typeof(DbAttribute), true) is DbAttribute att) // Attributes + { + att.Init(fi, this); + + this.baseAttributes.Add(att); + this.attributeAttributes.Add(att); + } + else if (fi.GetCustomAttribute(typeof(DbForeignKey), true) is DbForeignKey fkey) // ForeignKeys + { + fkey.Init(fi, this); + + this.baseAttributes.Add(fkey); + this.foreignKeyAttributes.Add(fkey); + } + else if (fi.GetCustomAttribute(typeof(DbForeignObject), true) is DbForeignObject fobj) // ForeignObjects + { + fobj.Init(fi, this); + + this.foreignObjectAttributes.Add(fobj); + } + } + catch(InvalidOperationException ex) + { + throw new InvalidOperationException($"Cannot init foreignObject-field '{fi.Name}' of '{classType.Name}'. {ex.Message}", ex); + } + } + } } } diff --git a/Database-Attribute_System/ClassAction.cs b/Database-Attribute_System/ClassAction.cs index c5219f9..11724c5 100644 --- a/Database-Attribute_System/ClassAction.cs +++ b/Database-Attribute_System/ClassAction.cs @@ -8,6 +8,29 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System { public class ClassAction { + private static List initiatedClassTypes = new List() { }; + /// + /// Initiates the attribute-system and preloads all necessary information + /// INFO: Will initiate necessary foreignObjects recursively! + /// If an class is already initiated, it will be ignored! + /// + /// The classType to preload + /// DbObject-attribute corresponding to the class + public static DbObject Init(Type classType) + { + // Check if given class is marked as dbObject + if (!(classType.GetCustomAttribute(typeof(DbObject), true) is DbObject dbObject)) throw new InvalidOperationException($"Cannot init '{classType.Name}'. Missing Attribute 'DbObject'"); + + if (!initiatedClassTypes.Contains(classType)) + { + dbObject.Init(classType); // Init dbObject + initiatedClassTypes.Add(classType); // Set it to the list + } + + return dbObject; + } + + /// /// Fills an given dbObject with given data /// Data-attribute-names and class-fieldNames have to match! (non case-sensitive) @@ -16,55 +39,23 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System /// Given object (marked with Db-attributes) /// The data /// This checks if any class-field and data-attribute does not exists in either (Slower) - public static void FillObject(T classObject, Dictionary data, bool runDataLossChecks = true) + public static void FillObject(T classObject, Dictionary data) { Type classType = classObject.GetType(); - string tableName = Function.GetDbTableName(classType); - - // Get class-fields - Dictionary dbFields = Function.ReadDbClassFields(classType); - - if (runDataLossChecks) - { - // Check every data-attribute for match in class-fields - foreach (KeyValuePair data_keySet in data) - { - bool isFound = false; - foreach (KeyValuePair field_keySet in dbFields) - { - if (field_keySet.Key.ToLower() == data_keySet.Key.ToLower()) - isFound = true; - } - - if (!isFound) - throw new InvalidOperationException($"Could not fill object. Data-Attribute '{data_keySet.Key}' was not found in class!"); - } - // Check every class-field for match in data-attributes - foreach (KeyValuePair field_keySet in dbFields) - { - bool isFound = false; - foreach (KeyValuePair data_keySet in data) - { - if (field_keySet.Key.ToLower() == data_keySet.Key.ToLower()) - isFound = true; - } - - if (!isFound) - throw new InvalidOperationException($"Could not fill object. Class-field '{field_keySet.Key}' was not found in data!"); - } - } + // Read dbObject-attribute + DbObject dbObject = ClassAction.Init(classType); // Iterate through data foreach (KeyValuePair data_keySet in data) { // Interate through class-fields - foreach (KeyValuePair field_keySet in dbFields) + foreach (BaseAttribute baseAttribute in dbObject.baseAttributes) { // If its a match, set the value - if (field_keySet.Key.ToLower() == data_keySet.Key.ToLower()) + if (baseAttribute._attributeName.ToLower() == data_keySet.Key.ToLower()) { - field_keySet.Value.SetValue(classObject, data_keySet.Value); + baseAttribute.parentField.SetValue(classObject, data_keySet.Value); break; } } @@ -79,57 +70,54 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System /// Given object (marked with Db-attributes) /// Function to handle query-calls - Has to return Dictionary[attributeName, attributeValue] /// This checks if any class-field and data-attribute does not exists in either (Slower) - public static T GetByPrimaryKey(Type classType, object primaryKeyValue, Func>> queryExecutor, bool runDataLossChecks = true) where T : new() + public static T GetByPrimaryKey(Type classType, object primaryKeyValue, Func>> queryExecutor) where T : new() { Dictionary primaryKeyData = new Dictionary() { }; primaryKeyData.Add(null, primaryKeyValue); - return GetByPrimaryKey(classType, primaryKeyData, queryExecutor, runDataLossChecks); + return GetByPrimaryKey(classType, primaryKeyData, queryExecutor); } - public static T GetByPrimaryKey(Type classType, string primaryKeyName, object primaryKeyValue, Func>> queryExecutor, bool runDataLossChecks = true) where T : new() + public static T GetByPrimaryKey(Type classType, string primaryKeyName, object primaryKeyValue, Func>> queryExecutor) where T : new() { Dictionary primaryKeyData = new Dictionary() { }; primaryKeyData.Add(primaryKeyName, primaryKeyValue); - return GetByPrimaryKey(classType, primaryKeyData, queryExecutor, runDataLossChecks); + return GetByPrimaryKey(classType, primaryKeyData, queryExecutor); } - public static T GetByPrimaryKey(Type classType, Dictionary primaryKeyData, Func>> queryExecutor, bool runDataLossChecks = true) where T: new() + public static T GetByPrimaryKey(Type classType, Dictionary primaryKeyData, Func>> queryExecutor) where T: new() { // Create new empty object T obj = new T(); - // Read all fields - Dictionary dbFields = Function.ReadDbClassFields(classType); + // Read dbObject-attribute + DbObject dbObject = ClassAction.Init(classType); + // iterate thru them to check and fill object - foreach (KeyValuePair field in dbFields) + foreach (DbPrimaryKey primaryKeyAtt in dbObject.primaryKeyAttributes) { - // primaryKeys - if (field.Value.GetCustomAttribute(typeof(DbPrimaryKey), true) is DbPrimaryKey pkey) - { - bool dataMatchFound = false; + bool dataMatchFound = false; - // Now search the corresponding primaryKeyData - foreach (KeyValuePair primaryKey in primaryKeyData) + // Now search the corresponding primaryKeyData + foreach (KeyValuePair primaryKey in primaryKeyData) + { + // primaryKey matches + if(primaryKeyAtt._attributeName.ToLower() == primaryKey.Key.ToLower()) { - // primaryKey matches - if(field.Value.Name.ToLower() == primaryKey.Key.ToLower()) - { - // Set data - field.Value.SetValue(obj, primaryKey.Value); - - dataMatchFound = true; - break; - } - } + // Set data + primaryKeyAtt.parentField.SetValue(obj, primaryKey.Value); - // If no data was found matching this field - if (!dataMatchFound) throw new InvalidOperationException($"Cannot create object with primaryKeyData. No data assigned to field '{field.Value.Name}'"); + dataMatchFound = true; + break; + } } + + // If no data was found matching this field + if (!dataMatchFound) throw new InvalidOperationException($"Cannot create object with primaryKeyData. No data assigned to field '{primaryKeyAtt.parentField.Name}'"); } string query = QueryBuilder.SelectByPrimaryKey(obj); // Generate query List> dataSet = queryExecutor(query); // Execute - FillObject(obj, dataSet[0], runDataLossChecks); // Fill the object + FillObject(obj, dataSet[0]); // Fill the object return obj; } @@ -142,21 +130,22 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System /// class-fields for select /// Function to handle query-calls - Has to return Dictionary[attributeName, attributeValue] /// This checks if any class-field and data-attribute does not exists in either (Slower) - /// - public static List GetListByAttribute(Type classType, Dictionary fields, Func>> queryExecutor, bool runDataLossChecks = true) where T : new() + /// List of dbObjects + public static List GetListByAttribute(Type classType, Dictionary fields, Func>> queryExecutor) where T : new() { - string tableName = Function.GetDbTableName(classType); // Get database-tableName + // Read dbObject-attribute + DbObject dbObject = ClassAction.Init(classType); Function.ConvertAttributeToDbAttributes(classType, fields); - string query = QueryBuilder.SelectByAttribute(tableName, fields); // Generate query + string query = QueryBuilder.SelectByAttribute(dbObject._tableName, fields); // Generate query List> dataSet = queryExecutor(query); // Execute List objs = new List() { }; foreach(Dictionary data in dataSet) { T obj = new T(); // New object - FillObject(obj, data, runDataLossChecks); // Fill it + FillObject(obj, data); // Fill it objs.Add(obj); // Add to list } @@ -174,32 +163,27 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System /// Function to handle query-calls - Has to return Dictionary[attributeName, attributeValue] /// Determents how deep resolving will be executed /// This checks if any class-field and data-attribute does not exists in either (Slower) - public static void ResolveForeignKeys(T classObject, Func>> queryExecutor, int max_depth = 1, bool runDataLossChecks = true) where T: new() + public static void ResolveForeignKeys(T classObject, Func>> queryExecutor, int max_depth = 1) where T: new() { Type classType = classObject.GetType(); - // Get class-fields - Dictionary dbFields = Function.ReadDbClassFields(classType); + // Read dbObject-attribute + DbObject dbObject = ClassAction.Init(classType); - foreach (KeyValuePair dbField in dbFields) + foreach (DbForeignObject foreignObjectAtt in dbObject.foreignObjectAttributes) { - // If field is foreignKey - if (dbField.Value.GetCustomAttribute(typeof(DbForeignKey), true) is DbForeignKey fkey) - { - FieldInfo f_Field = fkey._foreignKeyField; - object f_value = f_Field.GetValue(classObject); + object foreignObject_value = foreignObjectAtt.parentField.GetValue(classObject); - // When its empty, get it - if(f_value == null) - { - f_value = GetByPrimaryKey(classType, f_value, queryExecutor, runDataLossChecks); ; - } + // When its empty, get it + if(foreignObject_value == null) + { + foreignObject_value = GetByPrimaryKey(classType, foreignObjectAtt.foreignKeyAttribute.parentField.GetValue(classObject), queryExecutor); ; + } - // Recursive resolving - if (max_depth - 1 > 0) - { - ResolveForeignKeys(f_value, queryExecutor, max_depth - 1, runDataLossChecks); - } + // Recursive resolving + if (max_depth - 1 > 0) + { + ResolveForeignKeys(foreignObject_value, queryExecutor, max_depth - 1); } } } diff --git a/Database-Attribute_System/Database-Attribute_System.csproj b/Database-Attribute_System/Database-Attribute_System.csproj index 281ed9c..24e3b55 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.4.1 + 1.5 diff --git a/Database-Attribute_System/QueryBuilder.cs b/Database-Attribute_System/QueryBuilder.cs index 58cb2ec..dd8262f 100644 --- a/Database-Attribute_System/QueryBuilder.cs +++ b/Database-Attribute_System/QueryBuilder.cs @@ -18,17 +18,14 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System { Type classType = classObject.GetType(); - // Get db-table-name from class - string tableName = Function.GetDbTableName(classType); + // Read dbObject-attribute + DbObject dbObject = ClassAction.Init(classType); - // Get class db-fields - Dictionary dbPrimaryKeys = new Dictionary() { }; - Dictionary dbAttributes = new Dictionary() { }; - Dictionary dbForeignKeys = new Dictionary() { }; - Function.ReadDbClassFields(classObject, ref dbPrimaryKeys, ref dbAttributes, ref dbForeignKeys); - if (dbPrimaryKeys.Count == 0) throw new InvalidOperationException($"Cannot generate SQL-Query of '{classType.Name}'. No primary-key/s found!"); + // Check if 'byPrimaryKey' is possible + if (dbObject.primaryKeyAttributes.Count == 0) throw new InvalidOperationException($"Cannot generate SQL-Query of '{classType.Name}'. No primary-key/s!"); + Dictionary dbPrimaryKeys = Function.ReadFieldData(Function.ConvertToDerivedList(dbObject.primaryKeyAttributes), classObject); - return SelectByAttribute(tableName, dbPrimaryKeys); + return SelectByAttribute(dbObject._tableName, dbPrimaryKeys); } /// @@ -70,15 +67,14 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System { Type classType = classObject.GetType(); - // Get db-table-name from class - string tableName = Function.GetDbTableName(classType); + // Read dbObject-attribute + DbObject dbObject = ClassAction.Init(classType); - // Get class db-fields - Dictionary dbPrimaryKeys = new Dictionary() { }; - Dictionary dbAttributes = new Dictionary() { }; - Dictionary dbForeignKeys = new Dictionary() { }; - Function.ReadDbClassFields(classObject, ref dbPrimaryKeys, ref dbAttributes, ref dbForeignKeys); - if (dbPrimaryKeys.Count == 0) throw new InvalidOperationException($"Cannot generate SQL-Query of '{classType.Name}'. No primary-key/s found!"); + // Check if 'byPrimaryKey' is possible + if (dbObject.primaryKeyAttributes.Count == 0) throw new InvalidOperationException($"Cannot generate SQL-Query of '{classType.Name}'. No primary-key/s!"); + Dictionary dbPrimaryKeys = Function.ReadFieldData(Function.ConvertToDerivedList(dbObject.primaryKeyAttributes), classObject); + Dictionary dbForeignKeys = Function.ReadFieldData(Function.ConvertToDerivedList(dbObject.foreignKeyAttributes), classObject); + Dictionary dbAttributes = Function.ReadFieldData(Function.ConvertToDerivedList(dbObject.attributeAttributes), classObject); // Add foreign-keys to attributes foreach (KeyValuePair dbForeignKey in dbForeignKeys) @@ -89,7 +85,7 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System // Build set-parameters object[] paramSet = DbFunction.BuildKeyEqualQuery(dbAttributes, ", "); // Add SQL-command part - paramSet[0] = $"UPDATE {tableName} SET "+ paramSet[0]; + paramSet[0] = $"UPDATE {dbObject._tableName} SET "+ paramSet[0]; // Build where-parameters object[] paramWhere = DbFunction.BuildKeyEqualQuery(dbPrimaryKeys, " AND "); @@ -111,18 +107,15 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System { Type classType = classObject.GetType(); - // Get db-table-name from class - string tableName = Function.GetDbTableName(classType); + // Read dbObject-attribute + DbObject dbObject = ClassAction.Init(classType); - // Get class db-fields - Dictionary dbPrimaryKeys = new Dictionary() { }; - Dictionary dbAttributes = new Dictionary() { }; - Dictionary dbForeignKeys = new Dictionary() { }; - Function.ReadDbClassFields(classObject, ref dbPrimaryKeys, ref dbAttributes, ref dbForeignKeys); - if (dbPrimaryKeys.Count == 0) throw new InvalidOperationException($"Cannot generate SQL-Query of '{classType.Name}'. No primary-key/s found!"); + // Check if 'byPrimaryKey' is possible + if (dbObject.primaryKeyAttributes.Count == 0) throw new InvalidOperationException($"Cannot generate SQL-Query of '{classType.Name}'. No primary-key/s!"); + Dictionary dbPrimaryKeys = Function.ReadFieldData(Function.ConvertToDerivedList(dbObject.primaryKeyAttributes), classObject); // Build and return the query - return DeleteByAttribute(tableName, dbPrimaryKeys); + return DeleteByAttribute(dbObject._tableName, dbPrimaryKeys); } public static string DeleteByAttribute(string tableName, Dictionary dbAttributes = null) diff --git a/Database-Attribute_System/internal/Function.cs b/Database-Attribute_System/internal/Function.cs index 6fee030..943acff 100644 --- a/Database-Attribute_System/internal/Function.cs +++ b/Database-Attribute_System/internal/Function.cs @@ -31,20 +31,65 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System } } + internal static List ConvertToDerivedList(List list) + { + List derivedList = new List() { }; + foreach (BaseAttribute key in list) + { + derivedList.Add(key); + } + return derivedList; + } + internal static List ConvertToDerivedList(List list) + { + List derivedList = new List() { }; + foreach (BaseAttribute key in list) + { + derivedList.Add(key); + } + return derivedList; + } + internal static List ConvertToDerivedList(List list) + { + List derivedList = new List() { }; + foreach (BaseAttribute key in list) + { + derivedList.Add(key); + } + return derivedList; + } + + internal static Dictionary ReadFieldData(List fieldAttributes, T classObject) + { + Dictionary fieldData = new Dictionary() { }; + + foreach (BaseAttribute attribute in fieldAttributes) + { + // Read the data and add it + fieldData.Add( + attribute._attributeName, + attribute.parentField.GetValue(classObject) + ); + } + + return fieldData; // Return the data + } + internal static void ConvertAttributeToDbAttributes(Type classType, Dictionary attributeNameAndValues) { - Dictionary classFields = ReadDbClassFields(classType); + // Read dbObject-attribute + DbObject dbObject = ClassAction.Init(classType); foreach (KeyValuePair attributeNameAndValue in attributeNameAndValues) { bool nameFound = false; - foreach (KeyValuePair classField in classFields) + foreach (BaseAttribute baseAttribute in dbObject.baseAttributes) { - if (attributeNameAndValue.Key.ToLower() == classField.Value.Name.ToLower()) + if (attributeNameAndValue.Key.ToLower() == baseAttribute.parentField.Name.ToLower()) { attributeNameAndValues.Remove(attributeNameAndValue.Key); - attributeNameAndValues.Add(classField.Key, attributeNameAndValue.Value); + attributeNameAndValues.Add(baseAttribute._attributeName, attributeNameAndValue.Value); nameFound = true; break; @@ -56,17 +101,17 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System } internal static void ConvertAttributeToDbAttributes(Type classType, List attributeNames) { - Dictionary classFields = ReadDbClassFields(classType); + // Read dbObject-attribute + DbObject dbObject = ClassAction.Init(classType); - List dbAttributes = new List() { }; - for(int i=0; i< attributeNames.Count; i++) + for(int i=0; i< dbObject.baseAttributes.Count; i++) { bool nameFound = false; - foreach (KeyValuePair classField in classFields) + foreach (BaseAttribute baseAttribute in dbObject.baseAttributes) { - if(attributeNames[i].ToLower() == classField.Value.Name.ToLower()) + if(attributeNames[i].ToLower() == baseAttribute.parentField.Name.ToLower()) { - attributeNames[i] = classField.Key; + attributeNames[i] = baseAttribute._attributeName; nameFound = true; break; @@ -77,77 +122,6 @@ namespace eu.railduction.netcore.dll.Database_Attribute_System } } - internal static void ReadDbClassFields(T classObject, ref Dictionary dbPrimaryKeys, ref Dictionary dbAttributes, ref Dictionary dbForeignKeys) - { - Type classType = typeof(T); - - // Reset lists (just in case) - dbPrimaryKeys = new Dictionary() { }; - dbAttributes = new Dictionary() { }; - dbForeignKeys = new Dictionary() { }; - - // Iterate thru all properties - foreach (System.Reflection.FieldInfo fi in classType.GetRuntimeFields()) - { - // Check if current field is a db-field - if (fi.GetCustomAttribute(typeof(DbPrimaryKey), true) is DbPrimaryKey pkey) // PrimaryKey - { - string dbAttributeName = pkey._attributeName ?? fi.Name; // If no alternative attribute-name is specified, use the property-name - object value = fi.GetValue(classObject); - dbPrimaryKeys.Add(dbAttributeName, value); - } - else if (fi.GetCustomAttribute(typeof(DbAttribute), true) is DbAttribute att) // Attributes - { - string dbAttributeName = att._attributeName ?? fi.Name; // If no alternative attribute-name is specified, use the property-name - object value = fi.GetValue(classObject); - dbAttributes.Add(dbAttributeName, value); - } - else if (fi.GetCustomAttribute(typeof(DbForeignKey), true) is DbForeignKey fkey) // ForeignKeys - { - string dbAttributeName = fkey._attributeName ?? fi.Name; // If no alternative attribute-name is specified, use the property-name - object value = fi.GetValue(classObject); - dbForeignKeys.Add(dbAttributeName, value); - } - } - } - - internal static Dictionary ReadDbClassFields(Type classType) - { - Dictionary dbFields = new Dictionary(); - - // Iterate thru all properties - foreach (System.Reflection.FieldInfo fi in classType.GetRuntimeFields()) - { - // Check if current field is a db-field - if (fi.GetCustomAttribute(typeof(DbPrimaryKey), true) is DbPrimaryKey pkey) // PrimaryKey - { - string dbAttributeName = pkey._attributeName ?? fi.Name; // If no alternative attribute-name is specified, use the property-name - dbFields.Add(dbAttributeName, fi); - } - else if (fi.GetCustomAttribute(typeof(DbAttribute), true) is DbAttribute att) // Attributes - { - string dbAttributeName = att._attributeName ?? fi.Name; // If no alternative attribute-name is specified, use the property-name - dbFields.Add(dbAttributeName, fi); - } - else if (fi.GetCustomAttribute(typeof(DbForeignKey), true) is DbForeignKey fkey) // ForeignKeys - { - string dbAttributeName = fkey._attributeName ?? fi.Name; // If no alternative attribute-name is specified, use the property-name - dbFields.Add(dbAttributeName, fi); - } - } - - return dbFields; - } - - public static string GetDbTableName(Type classType) - { - // Check if class has attribute 'DbObject' and get the database table-name - if (!(classType.GetCustomAttribute(typeof(DbObject), true) is DbObject dbObjectAttribute)) throw new InvalidOperationException($"Cannot generate SQL-Query of '{classType.Name}'. Missing Attribute 'DbObject'"); - string tableName = dbObjectAttribute._tableName ?? classType.Name; // If no alternative table-name is specified, use the class-name - - return tableName; - } - public static string SqlSerialise(object obj) {