You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OMS.NET/DbClass/SqlHelper.cs

196 lines
7.4 KiB
C#

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<TableAttribute>();
return attr?.TableName ?? throw new Exception($"{type.Name} 没有指定数据表");
}
public static bool IsIdentity(Type type)
{
var primaryKey = GetPrimaryKeyProperties(type);
return primaryKey.GetCustomAttribute<ColumnAttribute>()!.IsIdentity;
}
public static IEnumerable<PropertyInfo> GetProperties(Type type)
{
return type.GetProperties()
.Where(p => p.GetCustomAttribute<ColumnAttribute>() != null);
}
private static PropertyInfo GetPrimaryKeyProperties(Type type)
{
var primaryKeyProperties = GetProperties(type)
.Where(p => p.GetCustomAttribute<ColumnAttribute>()?.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<PropertyInfo> GetNonKeyProperties(Type type)
{
return GetProperties(type)
.Where(p => p.GetCustomAttribute<ColumnAttribute>()?.IsPrimaryKey == false);
}
private static PropertyInfo? GetIdentityKeyProperty(Type type)
{
var primaryKey = GetPrimaryKeyProperties(type);
return (primaryKey.GetCustomAttribute<ColumnAttribute>()!.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<ColumnAttribute>()!.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<ColumnAttribute>()!.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<ColumnAttribute>()!.ColumnName} = @{p.Name}"));
var primaryKey = GetPrimaryKeyProperties(type);
var whereClause = $"{primaryKey.GetCustomAttribute<ColumnAttribute>()!.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<ColumnAttribute>()!.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<ColumnAttribute>()!.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<ColumnAttribute>()!.ColumnName));
var primaryKey = GetPrimaryKeyProperties(type);
var whereClause = $"{primaryKey.GetCustomAttribute<ColumnAttribute>()!.ColumnName} = @{primaryKey.Name}";
return $"SELECT {columns} FROM {tableName} WHERE {whereClause}";
}
public static IEnumerable<T> SelectAll<T>() 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<T>();
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<ColumnAttribute>()!;
var value = reader[columnAttr.ColumnName];
if (value != DBNull.Value)
{
property.SetValue(obj, Convert.ChangeType(value, property.PropertyType));
}
}
}
public static T? Get<T>(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<ColumnAttribute>()!.ColumnName, key);
using var reader = command.ExecuteReader();
while (reader.Read())
{
var item = new T();
PopulateObject(reader, item);
return item;
}
return null;
}
}
}