using eu.railduction.netcore.dll.Database_Attribute_System.Attributes; using System; using System.Collections.Generic; using System.Reflection; using System.Text; 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) /// /// /// 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) { Type classType = classObject.GetType(); // Read dbObject-attribute DbObject dbObject = ClassAction.Init(classType); // Iterate through data foreach (KeyValuePair data_keySet in data) { // Interate through class-fields foreach (BaseAttribute baseAttribute in dbObject.baseAttributes) { // If its a match, set the value if (baseAttribute._attributeName.ToLower() == data_keySet.Key.ToLower()) { baseAttribute.parentField.SetValue(classObject, data_keySet.Value); break; } } } } /// /// Gets an dbObject by primaryKey/s /// /// /// Given object (marked with Db-attributes) /// Function to handle query-calls - Has to return Dictionary[attributeName, attributeValue] 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); } 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); } public static T GetByPrimaryKey(Type classType, Dictionary primaryKeyData, Func>> queryExecutor) where T: new() { // Create new empty object T obj = new T(); // Read dbObject-attribute DbObject dbObject = ClassAction.Init(classType); // iterate thru them to check and fill object foreach (DbPrimaryKey primaryKeyAtt in dbObject.primaryKeyAttributes) { bool dataMatchFound = false; // Now search the corresponding primaryKeyData foreach (KeyValuePair primaryKey in primaryKeyData) { // primaryKey matches if(primaryKeyAtt._attributeName.ToLower() == primaryKey.Key.ToLower()) { // Set data primaryKeyAtt.parentField.SetValue(obj, primaryKey.Value); 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}'"); } ResolveByPrimaryKey(obj, queryExecutor); return obj; } /// /// Resolves dbObject by primaryKey/s /// Object needs to have primaryKey/s set! /// /// /// Given object (marked with Db-attributes) /// Function to handle query-calls - Has to return Dictionary[attributeName, attributeValue] public static void ResolveByPrimaryKey(T classObject, Func>> queryExecutor) { string query = QueryBuilder.SelectByPrimaryKey(classObject); // Generate query List> dataSet = queryExecutor(query); // Execute FillObject(classObject, dataSet[0]); // Fill the object } /// /// Gets a list of dbObjects by attribute/s /// /// /// Type of class /// 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) /// List of dbObjects public static List GetListByAttribute(Type classType, Dictionary fields, Func>> queryExecutor) where T : new() { // Read dbObject-attribute DbObject dbObject = ClassAction.Init(classType); Function.ConvertAttributeToDbAttributes(classType, fields); 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); // Fill it objs.Add(obj); // Add to list } return objs; // Return list } /// /// Resolves all foreignKeys with the database /// Only works if the foreignKey is single (not assembled)! /// /// /// Given object (marked with Db-attributes) /// 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) where T: new() { Type classType = classObject.GetType(); // Read dbObject-attribute DbObject dbObject = ClassAction.Init(classType); foreach (DbForeignObject foreignObjectAtt in dbObject.foreignObjectAttributes) { object foreignObject_value = foreignObjectAtt.parentField.GetValue(classObject); // 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(foreignObject_value, queryExecutor, max_depth - 1); } } } } }