/// <summary> /// [A very dirty-feeling function] /// Given a description, and a type, attempts to find an entry in the database for the given type that has a certain description. /// /// For example, `getFromDescription<language>("C++")` would look for a language (in the language table) with the description of `C++` and then returns it. /// </summary> /// <typeparam name="T">The type to look for. This must be a database type.</typeparam> /// <param name="db">The database connection.</param> /// <param name="description">The description to look for.</param> /// <returns>Either null, if the value wasn't found, or the value that was found.</returns> public static T getFromDescription <T>(this DatabaseCon db, string description) where T : class { if (db == null) { throw new ArgumentNullException("db"); } if (description == null) { throw new ArgumentNullException("description"); } // Get the right set that represetns `T` var set = db._getSetFromT <T>(); // Then look through all of the values in the DbSet for it. foreach (var value in set) { // This is dirty... dynamic dyValue = value; if (dyValue.description == description) { return(value); } } return(null); }
/// <summary> /// Throws an exception if the given name/description (the field is called 'description' but is used more as a name) is already being used. /// /// NOTE: The type `T` must contain a field called 'description'. /// </summary> /// <typeparam name="T">The type to check with. (this determines which table is used)</typeparam> /// <param name="db">The database connection.</param> /// <param name="name_description">The name/description to check for.</param> public static void enforceNameIsUnique <T>(this DatabaseCon db, string name_description) where T : class { var set = db._getSetFromT <T>(); foreach (var record in set) { dynamic dyRecord = record; if (dyRecord.description == name_description) { throw new Exception($"The name/description '{name_description}' is already being used by another {typeof(T).Name}"); } } }
/// <summary> /// Throws an exception if the given bit index is already being used. /// /// NOTE: The type `T` must contain fields called `bit_index` and `description`. /// </summary> /// <typeparam name="T">The type to check with. (this determines which table is used)</typeparam> /// <param name="db">The database connection</param> /// <param name="index">The index to check</param> public static void enforceBitIndexIsUnique <T>(this DatabaseCon db, byte index) where T : class { var set = db._getSetFromT <T>(); foreach (var record in set) { dynamic dyRecord = record; if (dyRecord.bit_index == index) { throw new Exception($"The bit index {index} is being used by the {typeof(T).Name} '{dyRecord.description}'"); } } }
// The reason this function is in ViewHelper, instead of DataHelper, is because of the user-interaction is requires, as well as the requirement of the MainWindow, making it specialised for use in views. /// <summary> /// Deletes a `T` from the database that has a description matching the given description. /// (note: in a lot of cases the description is just a name, hence 'name_description') /// /// This function will first prompt the user with a message box, asking them to confirm the deletion of the object. /// /// It is a requirement that `T` has a field called `description`. /// </summary> /// <typeparam name="T">The database type to remove (and also determines the database table that's used)</typeparam> /// <param name="window">The main window, so it's status can be updated</param> /// <param name="name_description">The name/description of the object to remove</param> /// <returns>True if something was delete.</returns> public static bool deleteTByDescription <T>(MainWindow window, string name_description) where T : class { if (window == null) { throw new ArgumentNullException("window"); } if (name_description == null) { throw new ArgumentNullException("name_description"); } var TName = typeof(T).Name; var result = System.Windows.Forms.MessageBox.Show($"Are you sure you want to remove the {TName} '{name_description}'?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.No) { window.updateStatus($"Not going through with removal of the {TName}"); return(false); } using (var db = new DatabaseCon()) { var set = db._getSetFromT <T>(); T value = null; // I need to use dynamic, so can't use SingleOrDefault since it doesn't like lambdas apparently foreach (var val in set) { dynamic dyVal = val; if (dyVal.description == name_description) { value = val; break; } } if (value == null) { window.updateStatus($"Can't delete a(n) {TName} that doesn't exist"); return(false); } window.updateStatus($"Removing {TName} '{name_description}' from the database"); set.Remove(value); db.SaveChanges(); } return(true); }
/// <summary> /// Given a bitmask, returns a list of all objects of `T` from the database that the bitmask contains. /// /// For example, say `T` was `device_type`, and in the database we only had two devices: /// 1: 'Arduino' with a bit_index of 0 /// 2: 'PC' with a bit_index of 1 /// /// Now, imagine the bitmask of '00000001', the 0th bit is set to 1, so a list only containing 'Arduino' is returned. /// Take '00000011', both the 0th and 1st bits are set, so a list containing both 'Arduino' and 'PC' is returned. /// </summary> /// <typeparam name="T">The database type to use.</typeparam> /// <param name="db">The database connection.</param> /// <param name="bitmask">The bitmask to use.</param> /// <returns>See extended summary</returns> public static List <T> getFromBitmask <T>(this DatabaseCon db, byte bitmask) where T : class { var set = db._getSetFromT <T>(); // LINQ doesn't like using the _getBitIndex function during a query, so I go over it the old fashioned way. List <T> list = new List <T>(); foreach (var value in set) { if ((bitmask & (1 << value._getBitIndex())) > 0) { list.Add(value); } } return(list); }
/// <summary> /// Populates a drop down box (combobox) with the descriptions of `T` from the database. /// /// For example, if `T` were `device_type`, then the drop down would contain all of the descriptions/names of /// all the entries in the device_type table. /// /// It is a requirement that `T` contains a `description` field. /// </summary> /// <typeparam name="T">The database type to use</typeparam> /// <param name="db">The database connection</param> /// <param name="dropDown">The dropdown to populate</param> /// <param name="list">This list will be filled with all of the records from the table</param> /// <param name="additionalProcessing"> /// This function will be called with each record of `T` from the database, in case any additional action is required. /// /// The records are passed in order of description. /// /// This alleviates the need to then create another foreach right after this function, just to do some additional action. /// </param> public static void populateDropDownWithT <T>(this DatabaseCon db, System.Windows.Controls.ComboBox dropDown, out List <T> list, Action <T> additionalProcessing = null) where T : class { if (db == null) { throw new ArgumentNullException("db"); } if (dropDown == null) { throw new ArgumentNullException("dropDown"); } list = db._getSetFromT <T>().ToList(); foreach (var value in list.OrderBy(v => { dynamic dyV = v; return(dyV.description); })) { dynamic dyValue = value; dropDown.Items.Add(dyValue.description); additionalProcessing?.Invoke(value); } }