using System.Reflection; using MySql.Data.MySqlClient; using OMS.NET.Common; namespace OMS.NET.DbClass { [AttributeUsage(AttributeTargets.Class, Inherited = false)] public class TableAttribute : Attribute { public string TableName { get; } public TableAttribute(string tableName) { TableName = tableName; } } [AttributeUsage(AttributeTargets.Property, Inherited = false)] public class ColumnAttribute : Attribute { public string ColumnName { get; } public bool IsPrimaryKey { get; } public bool IsIdentity { get; } // 是否自增列 public ColumnAttribute(string columnName, bool isPrimaryKey = false, bool isIdentity = false) { ColumnName = columnName; IsPrimaryKey = isPrimaryKey; IsIdentity = isIdentity; } } public class SqlHelper { public static string GetTableName(Type type) { var attr = type.GetCustomAttribute(); return attr?.TableName ?? throw new Exception($"{type.Name} 没有指定数据表"); } public static bool IsIdentity(Type type) { var primaryKey = GetPrimaryKeyProperties(type); return primaryKey.GetCustomAttribute()!.IsIdentity; } public static IEnumerable GetProperties(Type type) { return type.GetProperties() .Where(p => p.GetCustomAttribute() != null); } private static PropertyInfo GetPrimaryKeyProperties(Type type) { var primaryKeyProperties = GetProperties(type) .Where(p => p.GetCustomAttribute()?.IsPrimaryKey == true) .ToList(); if (primaryKeyProperties.Count == 0) { throw new InvalidOperationException("No primary key defined for the class."); } if (primaryKeyProperties.Count != 1) { throw new InvalidOperationException("Multiple primary keys defined for the class. Only one primary key is allowed."); } return primaryKeyProperties.First(); } private static IEnumerable GetNonKeyProperties(Type type) { return GetProperties(type) .Where(p => p.GetCustomAttribute()?.IsPrimaryKey == false); } private static PropertyInfo? GetIdentityKeyProperty(Type type) { var primaryKey = GetPrimaryKeyProperties(type); return (primaryKey.GetCustomAttribute()!.IsIdentity == true) ? null : primaryKey; } public static string GetInsertSql(Type type) { var tableName = GetTableName(type); var identityKey = GetIdentityKeyProperty(type); var columns = GetNonKeyProperties(type) .Select(p => p.GetCustomAttribute()!.ColumnName).ToList(); var values = GetNonKeyProperties(type) .Select(p => "@" + p.Name).ToList(); if (identityKey != null) { // Exclude the identity key from columns and values for insert statement columns.Add(identityKey.GetCustomAttribute()!.ColumnName); values.Add("@" + identityKey.Name); } return $"INSERT INTO {tableName} ({string.Join(", ", columns)}) VALUES ({string.Join(", ", values)})"; } public static string GetUpdateSql(Type type) { var tableName = GetTableName(type); var setClause = string.Join(", ", GetNonKeyProperties(type) .Select(p => $"{p.GetCustomAttribute()!.ColumnName} = @{p.Name}")); var primaryKey = GetPrimaryKeyProperties(type); var whereClause = $"{primaryKey.GetCustomAttribute()!.ColumnName} = @{primaryKey.Name}"; return $"UPDATE {tableName} SET {setClause} WHERE {whereClause}"; } public static string GetDeleteSql(Type type) { var tableName = GetTableName(type); var primaryKey = GetPrimaryKeyProperties(type); var whereClause = $"{primaryKey.GetCustomAttribute()!.ColumnName} = @{primaryKey.Name}"; return $"DELETE FROM {tableName} WHERE {whereClause}"; } public static string GetSelectSql(Type type) { var tableName = GetTableName(type); var columns = string.Join(", ", GetProperties(type) .Select(p => p.GetCustomAttribute()!.ColumnName)); return $"SELECT {columns} FROM {tableName}"; } public static string GetSelectSqlWithPrimaryKey(Type type) { var tableName = GetTableName(type); var columns = string.Join(", ", GetProperties(type) .Select(p => p.GetCustomAttribute()!.ColumnName)); var primaryKey = GetPrimaryKeyProperties(type); var whereClause = $"{primaryKey.GetCustomAttribute()!.ColumnName} = @{primaryKey.Name}"; return $"SELECT {columns} FROM {tableName} WHERE {whereClause}"; } public static IEnumerable SelectAll() where T : SqlTable, new() { var type = typeof(T); var selectSql = GetSelectSql(type); using MySqlConnection connection = new(GlobalArea.ConnectionStringWithDbName); connection.Open(); // 确保在执行命令之前打开连接 using var command = new MySqlCommand(selectSql, connection); using var reader = command.ExecuteReader(); var results = new List(); while (reader.Read()) { var item = new T(); PopulateObject(reader, item); results.Add(item); } return results; } private static void PopulateObject(MySqlDataReader reader, SqlTable obj) { var type = obj.GetType(); foreach (var property in GetProperties(type)) { var columnAttr = property.GetCustomAttribute()!; var value = reader[columnAttr.ColumnName]; if (value != DBNull.Value) { property.SetValue(obj, Convert.ChangeType(value, property.PropertyType)); } } } public static T? Get(object key) where T : SqlTable, new() { var type = typeof(T); var selectSql = GetSelectSqlWithPrimaryKey(type); using MySqlConnection connection = new(GlobalArea.ConnectionStringWithDbName); connection.Open(); // 确保在执行命令之前打开连接 using var command = new MySqlCommand(selectSql, connection); var primaryKey = GetPrimaryKeyProperties(type); command.Parameters.AddWithValue("@" + primaryKey.GetCustomAttribute()!.ColumnName, key); using var reader = command.ExecuteReader(); while (reader.Read()) { var item = new T(); PopulateObject(reader, item); return item; } return null; } } }