diff --git a/MySqlPlus.Example/Program.cs b/MySqlPlus.Example/Program.cs index 9952ff1..9078171 100644 --- a/MySqlPlus.Example/Program.cs +++ b/MySqlPlus.Example/Program.cs @@ -1,4 +1,5 @@ -using System; +using MySql.Data.MySqlClient; +using System; namespace MontoyaTech.MySqlPlus.Example { @@ -32,19 +33,21 @@ namespace MontoyaTech.MySqlPlus.Example { var session = new MySqlSession("server=db.zone2d.com;user=root;database=zone2d;port=3306;password=-+W6!?Kv-6wDL2Vj5f=kC^Q&;SslMode=Required"); - //var car = new Car() { Make = "Chevy", Model = "Camaro" }; + session.Insert(new Car() { Make = "Chevy", Model = "Camaro", Year = 2011 }); - //session.Insert(car); + session.Insert(new Car() { Make = "GMC", Model = "Sierra", Year = 2000 }); - //car.Model = null; + var cars = session.GetAll(); - //session.Update(car); + foreach (var car in cars) + Console.WriteLine($"Make: {car.Make}, Model: {car.Model}, Year: {car.Year}"); - var car2 = session.Get(9); + cars[0].Make = "test"; - session.Insert(car2); + session.Update(cars[0]); - //session.Delete(car); + foreach (var car in cars) + session.Delete(car); Console.WriteLine("Done."); Console.ReadLine(); diff --git a/MySqlPlus/MySqlColumn.cs b/MySqlPlus/MySqlColumn.cs index 00fd5ee..c0a48dd 100644 --- a/MySqlPlus/MySqlColumn.cs +++ b/MySqlPlus/MySqlColumn.cs @@ -9,6 +9,11 @@ using System.Threading.Tasks; namespace MontoyaTech.MySqlPlus { + /// + /// The outline of a MySqlColumn attribute that specify's information about a field + /// and how it's setup in a MySql Row. + /// + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)] public class MySqlColumn : Attribute { public bool Id = false; diff --git a/MySqlPlus/MySqlColumnExtensions.cs b/MySqlPlus/MySqlColumnExtensions.cs new file mode 100644 index 0000000..64e4cdc --- /dev/null +++ b/MySqlPlus/MySqlColumnExtensions.cs @@ -0,0 +1,66 @@ +using Mysqlx.Resultset; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace MontoyaTech.MySqlPlus +{ + /// + /// A set of extensions to help work with MySqlColumns. + /// + public static class MySqlColumnExtensions + { + /// + /// Gets the FieldInfo and MySqlColumn for an Id column on a given row and returns + /// whether or not we found it. + /// + /// + /// + /// + /// + public static bool GetMySqlId(this T row, out FieldInfo idField, out MySqlColumn idColumn) + { + var type = typeof(T); + + return GetMySqlId(type, out idField, out idColumn); + } + + /// + /// Gets the FieldInfo and MySqlColumn for an Id column on a given row type and returns + /// whether or not we found it. + /// + /// + /// + /// + /// + public static bool GetMySqlId(this Type type, out FieldInfo idField, out MySqlColumn idColumn) + { + idField = null; + + idColumn = null; + + var fields = type.GetFields(); + + if (fields == null || fields.Length == 0) + return false; + + for (int i = 0; i < fields.Length; i++) + { + var column = fields[i].GetCustomAttribute(); + + if (column != null && column.Id) + { + idField = fields[i]; + idColumn = column; + + return true; + } + } + + return false; + } + } +} diff --git a/MySqlPlus/MySqlCommandExtensions.cs b/MySqlPlus/MySqlCommandExtensions.cs new file mode 100644 index 0000000..37005b5 --- /dev/null +++ b/MySqlPlus/MySqlCommandExtensions.cs @@ -0,0 +1,261 @@ +using MySql.Data.MySqlClient; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace MontoyaTech.MySqlPlus +{ + /// + /// A set of extensions to help work with MySqlCommands. + /// + public static class MySqlCommandExtensions + { + /// + /// Setups this MySqlCommand to insert a row in the db. + /// + /// + /// + /// + /// + public static void Insert(this MySqlCommand command, T row) + { + //Get the type of T + var type = typeof(T); + + //Get the row information. + var rowAttribute = type.GetCustomAttribute(); + + //Get all the fields. + var fields = type.GetFields(); + + if (fields == null || fields.Length == 0) + throw new Exception("Found no public fields on given row."); + + //Start building the query. + var builder = new StringBuilder(); + + //Write the insert section. + builder.Append($"INSERT INTO `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}` "); + + //Write the set values section. + builder.Append("SET "); + + bool seperate = false; + for (int i = 0; i < fields.Length; i++) + { + var column = fields[i].GetCustomAttribute(); + + if (column == null) + continue; + + //Skip id columns because they are auto incremented. + if (column.Id) + continue; + + if (seperate) + builder.Append(", "); + + builder.Append($"`{(string.IsNullOrWhiteSpace(column.Name) ? fields[i].Name : column.Name)}` = @{i}"); + + command.Parameters.AddWithValue($"@{i}", fields[i].GetValue(row)); + + seperate = true; + } + + //Set the command text. + command.CommandText = builder.ToString(); + } + + /// + /// Setups this MySqlCommand to update a row in the db. + /// + /// + /// + /// + /// + public static void Update(this MySqlCommand command, T row) + { + //Get the type of T + var type = typeof(T); + + //Get the row information. + var rowAttribute = type.GetCustomAttribute(); + + //Get all the fields. + var fields = type.GetFields(); + + if (fields == null || fields.Length == 0) + throw new Exception("Found no public fields on given row."); + + //Start building the query. + var builder = new StringBuilder(); + + //Write the update section + builder.Append($"UPDATE `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}` "); + + //Write the set values section + builder.Append("SET "); + + FieldInfo idField = null; + MySqlColumn idColumn = null; + bool seperate = false; + for (int i = 0; i < fields.Length; i++) + { + var column = fields[i].GetCustomAttribute(); + + if (column == null) + continue; + + //Skip id columns because they are auto incremented. + if (column.Id) + { + idField = fields[i]; + idColumn = column; + continue; + } + + if (seperate) + builder.Append(", "); + + builder.Append($"`{(string.IsNullOrWhiteSpace(column.Name) ? fields[i].Name : column.Name)}` = @{i}"); + + command.Parameters.AddWithValue($"@{i}", fields[i].GetValue(row)); + + seperate = true; + } + + //Make sure we have an id column. + if (idField == null) + throw new Exception("Given row does not contain an id column"); + + //Write the where clause + builder.Append($" WHERE `{(string.IsNullOrWhiteSpace(idColumn.Name) ? idField.Name : idColumn.Name)}`=@id LIMIT 1"); + + command.Parameters.AddWithValue("@id", idField.GetValue(row)); + + //Set the command text. + command.CommandText = builder.ToString(); + } + + /// + /// Setups this MySqlCommand to get a row from the db by it's id. + /// + /// + /// + /// + /// + public static void Get(this MySqlCommand command, ulong id) + { + //Get the type of T + var type = typeof(T); + + //Get the row information. + var rowAttribute = type.GetCustomAttribute(); + + //Get all the fields. + var fields = type.GetFields(); + + if (fields == null || fields.Length == 0) + throw new Exception("Found no public fields on given row."); + + //Get the id field + if (!type.GetMySqlId(out FieldInfo idField, out MySqlColumn idColumn)) + throw new Exception("Failed to find the id column on the given row."); + + //Set the command text. + command.CommandText = $"SELECT * FROM `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}` WHERE `{(string.IsNullOrWhiteSpace(idColumn.Name) ? idField.Name : idColumn.Name)}`=@id LIMIT 1"; + + //Add the id parameter. + command.Parameters.AddWithValue("@id", id); + } + + /// + /// Setups this MySqlCommand to get all the rows of a given type from the db. + /// + /// + /// + public static void GetAll(this MySqlCommand command) + { + //Get the type of T + var type = typeof(T); + + //Get the row information. + var rowAttribute = type.GetCustomAttribute(); + + //Set the command text. + command.CommandText = $"SELECT * FROM `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}`"; + } + + /// + /// Setups this MySqlCommand to delete a row from the db by it's id from an instance of the row. + /// + /// + /// + /// + /// + public static void Delete(this MySqlCommand command, T row) + { + //Get the type of T + var type = typeof(T); + + //Get the row information. + var rowAttribute = type.GetCustomAttribute(); + + //Start building the query. + var builder = new StringBuilder(); + + //Write the delete from section + builder.Append($"DELETE FROM `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}` "); + + //Get the id the column and field info + if (!row.GetMySqlId(out FieldInfo idField, out MySqlColumn idColumn)) + throw new Exception("Failed to find Id column on row."); + + //Write the where clause + builder.Append($"WHERE `{(string.IsNullOrWhiteSpace(idColumn.Name) ? idField.Name : idColumn.Name)}`=@id LIMIT 1"); + + //Add the id parameter. + command.Parameters.AddWithValue("@id", idField.GetValue(row)); + + //Set the command text. + command.CommandText = builder.ToString(); + } + + /// + /// Setups this MySqlCommand to delete a row from the db by it's id. + /// + /// + /// + /// + public static void Delete(this MySqlCommand command, ulong id) + { + //Get the type of T + var type = typeof(T); + + //Get the row information. + var rowAttribute = type.GetCustomAttribute(); + + //Start building the query. + var builder = new StringBuilder(); + + //Write the delete from section + builder.Append($"DELETE FROM `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}` "); + + //Get the id the column and field info + if (!type.GetMySqlId(out FieldInfo idField, out MySqlColumn idColumn)) + throw new Exception("Failed to find Id column on row."); + + //Write the where clause + builder.Append($"WHERE `{(string.IsNullOrWhiteSpace(idColumn.Name) ? idField.Name : idColumn.Name)}`=@id LIMIT 1"); + + //Add the id parameter. + command.Parameters.AddWithValue("@id", id); + + //Set the command text. + command.CommandText = builder.ToString(); + } + } +} diff --git a/MySqlPlus/MySqlDataReaderExtensions.cs b/MySqlPlus/MySqlDataReaderExtensions.cs new file mode 100644 index 0000000..9d556c2 --- /dev/null +++ b/MySqlPlus/MySqlDataReaderExtensions.cs @@ -0,0 +1,131 @@ +using MySql.Data.MySqlClient; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace MontoyaTech.MySqlPlus +{ + /// + /// A set of extensions to help work with a MySqlDataReader. + /// + public static class MySqlDataReaderExtensions + { + /// + /// Reads a row from a MySqlDataReader and returns an instance of the row. + /// This function will return null if it can't read the row. + /// + /// + /// + /// + public static T Read(this MySqlDataReader reader) + { + var row = typeof(T).CreateInstance(); + + if (Read(reader, row)) + return row; + + return default; + } + + /// + /// Reads a row from a MySqlDataReader into an existing instance of a row and + /// returns whether or not it succeeded + /// + /// + /// + /// + /// + /// + public static bool Read(this MySqlDataReader reader, T row) + { + if (!reader.Read()) + return false; + + var type = typeof(T); + + var fields = type.GetFields(); + + if (fields == null || fields.Length == 0) + throw new Exception("Found no public fields on given row."); + + for (int i = 0; i < fields.Length; i++) + { + var column = fields[i].GetCustomAttribute(); + + if (column == null) + continue; + else + column.ReadValue(row, fields[i], reader); + } + + return true; + } + + /// + /// Reads a row from a MySqlDataReader and returns whether or not it succeeded. + /// + /// + /// + /// + /// + public static bool Read(this MySqlDataReader reader, out T row) + { + row = default(T); + + if (!reader.Read()) + return false; + + var type = typeof(T); + + var fields = type.GetFields(); + + if (fields == null || fields.Length == 0) + throw new Exception("Found no public fields on given row."); + + row = type.CreateInstance(); + + for (int i = 0; i < fields.Length; i++) + { + var column = fields[i].GetCustomAttribute(); + + if (column == null) + continue; + else + column.ReadValue(row, fields[i], reader); + } + + return true; + } + + /// + /// Reads all the rows from a MySqlDataReader. + /// + /// + /// + /// + public static List ReadAll(this MySqlDataReader reader) + { + var rows = new List(); + + ReadAll(reader, rows); + + return rows; + } + + /// + /// Reads all the rows from a MySqlDataReader into an existing list. + /// + /// + /// + /// + public static void ReadAll(this MySqlDataReader reader, List rows) + { + while (reader.Read(out T row)) + rows.Add(row); + } + } +} diff --git a/MySqlPlus/MySqlPlus.csproj b/MySqlPlus/MySqlPlus.csproj index 5b99c77..33699d0 100644 --- a/MySqlPlus/MySqlPlus.csproj +++ b/MySqlPlus/MySqlPlus.csproj @@ -6,8 +6,24 @@ disable MontoyaTech.MySqlPlus MontoyaTech.MySqlPlus + MontoyaTech.MySqlPlus + 1.0.0 + MontoyaTech + A simple C# library to help work with MySql. + MontoyaTech 2023 + https://code.montoyatech.com/MontoyaTech/MySqlPlus + https://code.montoyatech.com/MontoyaTech/MySqlPlus + Logo_Symbol_Black_Outline.png + True + + + True + \ + + + diff --git a/MySqlPlus/MySqlRow.cs b/MySqlPlus/MySqlRow.cs index 57f0e4b..4249f5e 100644 --- a/MySqlPlus/MySqlRow.cs +++ b/MySqlPlus/MySqlRow.cs @@ -6,6 +6,11 @@ using System.Threading.Tasks; namespace MontoyaTech.MySqlPlus { + /// + /// The outline of a MySqlRow attribute that is used to specify + /// information about a MySqlRow. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] public class MySqlRow : Attribute { public string Name; diff --git a/MySqlPlus/MySqlSession.cs b/MySqlPlus/MySqlSession.cs index 20a6085..45f67e9 100644 --- a/MySqlPlus/MySqlSession.cs +++ b/MySqlPlus/MySqlSession.cs @@ -63,70 +63,22 @@ namespace MontoyaTech.MySqlPlus /// public ulong Insert(T row) { - var command = new MySqlCommand(); - - //Get the type of T - var type = typeof(T); - - //Get the row information. - var rowAttribute = type.GetCustomAttribute(); - - //Get all the fields. - var fields = type.GetFields(); - - if (fields == null || fields.Length == 0) - throw new Exception("Found no public fields on given row."); - - //Start building the query. - var builder = new StringBuilder(); - - //Write the insert section. - builder.Append($"INSERT INTO `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}` "); - - //Write the set values section. - builder.Append("SET "); - - FieldInfo idField = null; - bool seperate = false; - for (int i = 0; i < fields.Length; i++) + using (var command = new MySqlCommand()) { - var column = fields[i].GetCustomAttribute(); + command.Insert(row); - if (column == null) - continue; + this.Connection.ExecuteNonQuery(command); - //Skip id columns because they are auto incremented. - if (column.Id) + if (row.GetMySqlId(out FieldInfo idField, out MySqlColumn idColumn)) { - idField = fields[i]; - continue; + if (Type.GetTypeCode(idField.FieldType) == TypeCode.UInt64) + idField.SetValue(row, (ulong)command.LastInsertedId); + else + idField.SetValue(row, command.LastInsertedId); } - if (seperate) - builder.Append(", "); - - builder.Append($"`{(string.IsNullOrWhiteSpace(column.Name) ? fields[i].Name : column.Name)}` = @{i}"); - - command.Parameters.AddWithValue($"@{i}", fields[i].GetValue(row)); - - seperate = true; + return (ulong)command.LastInsertedId; } - - //Execute the insert command. - command.CommandText = builder.ToString(); - - this.Connection.ExecuteNonQuery(command); - - //Set the id on the row if we can. - if (idField != null) - { - if (Type.GetTypeCode(idField.FieldType) == TypeCode.UInt64) - idField.SetValue(row, (ulong)command.LastInsertedId); - else - idField.SetValue(row, command.LastInsertedId); - } - - return (ulong)command.LastInsertedId; } /// @@ -136,70 +88,12 @@ namespace MontoyaTech.MySqlPlus /// public void Update(T row) { - var command = new MySqlCommand(); - - //Get the type of T - var type = typeof(T); - - //Get the row information. - var rowAttribute = type.GetCustomAttribute(); - - //Get all the fields. - var fields = type.GetFields(); - - if (fields == null || fields.Length == 0) - throw new Exception("Found no public fields on given row."); - - //Start building the query. - var builder = new StringBuilder(); - - //Write the update section - builder.Append($"UPDATE `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}` "); - - //Write the set values section - builder.Append("SET "); - - FieldInfo idField = null; - MySqlColumn idColumn = null; - bool seperate = false; - for (int i = 0; i < fields.Length; i++) + using (var command = new MySqlCommand()) { - var column = fields[i].GetCustomAttribute(); + command.Update(row); - if (column == null) - continue; - - //Skip id columns because they are auto incremented. - if (column.Id) - { - idField = fields[i]; - idColumn = column; - continue; - } - - if (seperate) - builder.Append(", "); - - builder.Append($"`{(string.IsNullOrWhiteSpace(column.Name) ? fields[i].Name : column.Name)}` = @{i}"); - - command.Parameters.AddWithValue($"@{i}", fields[i].GetValue(row)); - - seperate = true; + this.Connection.ExecuteNonQuery(command); } - - //Make sure we have an id column. - if (idField == null) - throw new Exception("Given row does not contain an id column"); - - //Write the where clause - builder.Append($" WHERE `{(string.IsNullOrWhiteSpace(idColumn.Name) ? idField.Name : idColumn.Name)}`=@id LIMIT 1"); - - command.Parameters.AddWithValue("@id", idField.GetValue(row)); - - //Execute the command. - command.CommandText = builder.ToString(); - - this.Connection.ExecuteNonQuery(command); } /// @@ -210,7 +104,7 @@ namespace MontoyaTech.MySqlPlus /// public T Get(ulong id) { - var instance = typeof(T).ForceCreateInstanceFromType(); + var instance = typeof(T).CreateInstance(); this.Get(instance, id); @@ -225,67 +119,28 @@ namespace MontoyaTech.MySqlPlus /// public void Get(T row, ulong id) { - var command = new MySqlCommand(); - - //Get the type of T - var type = typeof(T); - - //Get the row information. - var rowAttribute = type.GetCustomAttribute(); - - //Get all the fields. - var fields = type.GetFields(); - - if (fields == null || fields.Length == 0) - throw new Exception("Found no public fields on given row."); - - //Find the id field - FieldInfo idField = null; - MySqlColumn idColumn = null; - for (int i = 0; i < fields.Length; i++) + using (var command = new MySqlCommand()) { - var column = fields[i].GetCustomAttribute(); + command.Get(id); - if (column != null && column.Id) - { - idField = fields[i]; - idColumn = column; - break; - } + using (var reader = this.Connection.ExecuteReader(command)) + reader.Read(row); } + } - //Make sure we have an id field. - if (idField == null) - throw new Exception("Failed to find id column for row."); - - command.CommandText = $"SELECT * FROM `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}` WHERE `{(string.IsNullOrWhiteSpace(idColumn.Name) ? idField.Name : idColumn.Name)}`=@id LIMIT 1"; - command.Parameters.AddWithValue("@id", id); - - using (var reader = this.Connection.ExecuteReader(command)) + /// + /// Gets all the rows of a given type in the db. + /// + /// + /// + public List GetAll() + { + using (var command = new MySqlCommand()) { - if (reader.Read()) - { - for (int i = 0; i < fields.Length; i++) - { - var column = fields[i].GetCustomAttribute(); + command.GetAll(); - if (column == null) - { - continue; - } - else if (column.Id) - { - if (Type.GetTypeCode(fields[i].FieldType) == TypeCode.UInt64) - fields[i].SetValue(row, (ulong)id); - else - fields[i].SetValue(row, (long)id); - } - else - { - column.ReadValue(row, fields[i], reader); - } - } - } + using (var reader = this.Connection.ExecuteReader(command)) + return reader.ReadAll(); } } @@ -296,53 +151,27 @@ namespace MontoyaTech.MySqlPlus /// public void Delete(T row) { - var command = new MySqlCommand(); - - //Get the type of T - var type = typeof(T); - - //Get the row information. - var rowAttribute = type.GetCustomAttribute(); - - //Get all the fields. - var fields = type.GetFields(); - - if (fields == null || fields.Length == 0) - throw new Exception("Found no public fields on given row."); - - //Start building the query. - var builder = new StringBuilder(); - - //Write the delete from section - builder.Append($"DELETE FROM `{(rowAttribute == null || string.IsNullOrWhiteSpace(rowAttribute.Name) ? type.Name : rowAttribute.Name)}` "); - - //Find the id column. - FieldInfo idField = null; - MySqlColumn idColumn = null; - for (int i = 0; i < fields.Length; i++) + using (var command = new MySqlCommand()) { - var column = fields[i].GetCustomAttribute(); + command.Delete(row); - if (column != null && column.Id) - { - idField = fields[i]; - idColumn = column; - break; - } + this.Connection.ExecuteNonQuery(command); } + } - //Make sure we found the id - if (idField == null) - throw new Exception("Failed to find id column for row."); + /// + /// Deletes a row in the db by it's id. + /// + /// + /// + public void Delete(ulong id) + { + using (var command = new MySqlCommand()) + { + command.Delete(id); - //Write the where clause - builder.Append($"WHERE `{(string.IsNullOrWhiteSpace(idColumn.Name) ? idField.Name : idColumn.Name)}`=@id LIMIT 1"); - - command.Parameters.AddWithValue("@id", idField.GetValue(row)); - - command.CommandText = builder.ToString(); - - this.Connection.ExecuteNonQuery(command); + this.Connection.ExecuteNonQuery(command); + } } /// diff --git a/MySqlPlus/TypeExentions.cs b/MySqlPlus/TypeExentions.cs index 0845f0b..af4bc2c 100644 --- a/MySqlPlus/TypeExentions.cs +++ b/MySqlPlus/TypeExentions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -11,7 +12,13 @@ namespace MontoyaTech.MySqlPlus /// internal static class TypeExentions { - public static T ForceCreateInstanceFromType(this Type type) + /// + /// Creates an instance of a given type. + /// + /// + /// + /// + public static T CreateInstance(this Type type) { if (type == null) return default; @@ -32,6 +39,13 @@ namespace MontoyaTech.MySqlPlus return default; } + /// + /// Converts a given object to a given type with better auto conversion support. + /// + /// + /// + /// + /// public static T ConvertToType(this object obj) { if (obj == null)