Files
hjha-server/GameDAL/db/Sql/ADOExtensions.cs
xiaoou e9616125ce feat: initial commit - HJHA game server full source
6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) +
game logic (GameFix/GameDAL/ServerData) +
network layer (NetWorkMessage) +
data layer (ObjectModel) +
utilities (MrWu/Core/Config/CloudAPI/dll) +
adapters (zyxAdapter/base)

.NET 8.0 C# solution, 16 projects, 958 source files
2026-07-07 12:02:15 +08:00

615 lines
25 KiB
C#

using System.Data;
using System.Linq;
using System;
using System.Collections.Generic;
using System.Collections;
using System.Reflection;
using System.Collections.ObjectModel;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using MrWu.Debug;
/// <summary>
/// ADOExtensions
/// </summary>
public static partial class ADOExtensions {
static MethodInfo GetColumeValueMethod { get; }
#region DataTable Extensions
/// <summary>
/// TryGetValue from DataTable
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="table"></param>
/// <param name="columnName"></param>
/// <param name="value"></param>
/// <param name="rowNumber"></param>
/// <returns></returns>
public static bool TryGetValue<TValue>(this DataTable table, string columnName, out TValue value, int rowNumber = 0) {
if (table.Rows.Count > rowNumber) {
value = table.Rows[rowNumber].GetValue<TValue>(columnName);
return true;
}
value = default(TValue);
return false;
}
/// <summary>
/// GetValue from DataTable
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="table"></param>
/// <param name="columnName"></param>
/// <param name="rowNumber"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public static TValue GetValue<TValue>(this DataTable table, string columnName, int rowNumber = 0, TValue defaultValue = default(TValue)) {
return table.TryGetValue<TValue>(columnName, out var outValue, rowNumber) ? outValue : defaultValue;
}
/// <summary>
/// Select
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="table"></param>
/// <param name="selector"></param>
/// <returns></returns>
public static IEnumerable<TObject> Select<TObject>(this DataTable table, Func<DataRow, TObject> selector) {
foreach (DataRow row in table.Rows) {
yield return selector.Invoke(row);
}
}
/// <summary>
/// ToObjects
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="table"></param>
/// <returns></returns>
public static IEnumerable<TObject> ToObjects<TObject>(this DataTable table) where TObject : new() {
foreach (DataRow row in table.Rows) {
yield return row.ToObject<TObject>();
}
}
#endregion
#region DataRow Extensions
#region
#region
/// <summary>
/// GetValue
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="row">DataRow</param>
/// <param name="column">DataColumn</param>
/// <returns></returns>
public static TValue GetColumeValue<TValue>(this DataRow row, DataColumn column) {
var columnValue = row[column];
if (columnValue is TValue value) {
return value;
}
if (columnValue is DBNull && column.AllowDBNull) {
return default(TValue);
}
throw new ArgumentOutOfRangeException($"无效的泛型类型,列名:{column.ColumnName},泛型类型为:{typeof(TValue)},数据列类型为:{GetColumnDataType(column)}");
}
/// <summary>
/// GetValue from DataRow
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="row"></param>
/// <param name="columnName"></param>
/// <returns></returns>
public static TValue GetValue<TValue>(this DataRow row, string columnName) {
if (row.TryGetColumn(columnName, out var column)) {
return row.GetColumeValue<TValue>(column);
}
throw new ArgumentOutOfRangeException("未找到字段:" + columnName);
}
#endregion
#region
static ConcurrentDictionary<Type, ICollection<MemberInfo>> memberInfoOfType = new ConcurrentDictionary<Type, ICollection<MemberInfo>>();
/// <summary>
/// ToObject from DataRow
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <param name="row"></param>
/// <returns></returns>
public static TObject ToObject<TObject>(this DataRow row) where TObject : new() {
var type = typeof(TObject);
var objectMembers = memberInfoOfType.GetOrAdd(type, t => {
var collection = new Collection<MemberInfo>();
foreach (var item in type.GetProperties().Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0)) {
collection.Add(item);
}
foreach (var item in type.GetFields().Where(p => !p.IsInitOnly && p.IsPublic)) {
collection.Add(item);
}
return collection;
});
var obj = new TObject();
foreach (var item in objectMembers) {
if (item is FieldInfo fieldInfo) {
row.TrySetMemberValue(obj, fieldInfo.Name, fieldInfo.FieldType, fieldInfo.SetValue);
} else if (item is PropertyInfo propertyInfo) {
row.TrySetMemberValue(obj, propertyInfo.Name, propertyInfo.PropertyType, propertyInfo.SetValue);
}
}
return obj;
}
static void TrySetMemberValue(this DataRow row, object parent, string memberName, Type memberType, Action<object, object> valueSetMethod) {
var column = row.Table.Columns[memberName];
if (column != null) {
var value = row[column];
try {
if (value != null && !(value is DBNull)) {
var sourceType = value.GetType();
if (memberType.IsEnum) {
value = Enum.ToObject(memberType, value);
} else if (memberType.IsGenericType && memberType.GetGenericTypeDefinition() == typeof(Nullable<>)) {
//目标类型为 Nullable<>,无需转换,可直接赋值
} else if (!sourceType.IsAssignableFrom(memberType) && value is IConvertible convert) {
value = convert.ToType(memberType, null);
}
valueSetMethod.Invoke(parent, value);
}
} catch (Exception ex) {
throw new ArgumentException($"TrySetMemberValue 数据类型定义错误, 定义类型与数据库类型不一致, 成员名:{memberName}, 当前泛型参数类型为: {memberType}, 实际数据类型:{ GetColumnDataType(row.Table.Columns[memberName])}, data: {value}", ex);
}
}
}
/// <summary>
/// ToDictionary from DataRow
/// </summary>
/// <param name="row"></param>
/// <returns></returns>
public static IDictionary<string, object> ToDictionary(this DataRow row) {
var columns = row.Table.Columns;
var dict = new Dictionary<string, object>();
foreach (DataColumn column in columns) {
var value = row.GetValue(column);
dict.Add(column.ColumnName, value);
}
return dict;
}
#endregion
#endregion
#region
/// <summary>
/// TryGetValue
/// </summary>
/// <param name="row"></param>
/// <param name="columnName"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool TryGetValue(this DataRow row, string columnName, out object value) {
if (row.TryGetColumn(columnName, out var column)) {
value = row.GetValue(column);
return true;
}
value = null;
return false;
}
/// <summary>
///
/// </summary>
/// <param name="row"></param>
/// <param name="column"></param>
/// <returns></returns>
public static object GetValue(this DataRow row, DataColumn column) {
var columnType = GetColumnDataType(column);
var value = row[column];
return value is DBNull ? null : value;
}
/// <summary>
///
/// </summary>
/// <param name="column"></param>
/// <returns></returns>
public static Type GetColumnDataType(this DataColumn column) => column.AllowDBNull && column.DataType.IsValueType ? typeof(Nullable<>).MakeGenericType(column.DataType) : column.DataType;
/// <summary>
/// TryGetColumn from DataRow
/// </summary>
/// <param name="row"></param>
/// <param name="columnName"></param>
/// <param name="column"></param>
/// <returns></returns>
public static bool TryGetColumn(this DataRow row, string columnName, out DataColumn column) {
column = row.Table.Columns[columnName];
return column != null;
}
internal static int SQLValue(this bool value) => value ? 1 : 0;
#endregion
#endregion
#region SQL命令扩展
#region
private static string connectionString { get; }
#endregion
#region
public static DataTable ExecuteTable(this dbbase db, string sqlText, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.FillTable(), parameters);
}
public static DataTable ExecuteTable(this dbbase db, string sqlText, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.FillTable(), type, parameters);
}
public static Task<DataTable> ExecuteTableAsync(this dbbase db, string sqlText, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, async cmd => await cmd.FillTableAsync(), parameters);
}
public static Task<DataTable> ExecuteTableAsync(this dbbase db, string sqlText, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, async cmd => await cmd.FillTableAsync(), type, parameters);
}
#endregion
#region
public static DataTable[] ExecuteTables(this dbbase db, string sqlText, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.FillTables(), parameters);
}
public static DataTable[] ExecuteTables(this dbbase db, string sqlText, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.FillTables(), type, parameters);
}
public static Task<DataTable[]> ExecuteTablesAsync(this dbbase db, string sqlText, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, async cmd => await cmd.FillTablesAsync(), parameters);
}
public static Task<DataTable[]> ExecuteTablesAsync(this dbbase db, string sqlText, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, async cmd => await cmd.FillTablesAsync(), type, parameters);
}
#endregion
#region SQL
public static int ExecuteNonQuery(this dbbase db, string sqlText, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.ExecuteNonQuery(), parameters);
}
public static int ExecuteNonQuery(this dbbase db, string sqlText, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.ExecuteNonQuery(), type, parameters);
}
public static Task<int> ExecuteNonQueryAsync(this dbbase db, string sqlText, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, cmd => cmd.ExecuteNonQueryAsync(), parameters);
}
public static Task<int> ExecuteNonQueryAsync(this dbbase db, string sqlText, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, cmd => cmd.ExecuteNonQueryAsync(), type, parameters);
}
#endregion
#region
public static object ExecuteScalar(this dbbase db, string sqlText, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.ExecuteScalar(), parameters);
}
public static object ExecuteScalar(this dbbase db, string sqlText, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.ExecuteScalar(), type, parameters);
}
public static Task<object> ExecuteScalarAsync(this dbbase db, string sqlText, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, cmd => cmd.ExecuteScalarAsync(), parameters);
}
public static Task<object> ExecuteScalarAsync(this dbbase db, string sqlText, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, cmd => cmd.ExecuteScalarAsync(), type, parameters);
}
#endregion
#region
#region
public static IEnumerable<TResult> ExecuteEntities<TResult>(this dbbase db, string sqlText, Func<DataRow, TResult> resultSelector, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.FillTable().Select(p => resultSelector.Invoke(p)), parameters);
}
public static IEnumerable<TResult> ExecuteEntities<TResult>(this dbbase db, string sqlText, Func<DataRow, TResult> resultSelector, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => cmd.FillTable().Select(p => resultSelector.Invoke(p)), type, parameters);
}
public static Task<IEnumerable<TResult>> ExecuteEntitiesAsync<TResult>(this dbbase db, string sqlText, Func<DataRow, TResult> resultSelector, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, async cmd => (await cmd.FillTableAsync()).Select(p => resultSelector.Invoke(p)), parameters);
}
public static Task<IEnumerable<TResult>> ExecuteEntitiesAsync<TResult>(this dbbase db, string sqlText, Func<DataRow, TResult> resultSelector, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, async cmd => (await cmd.FillTableAsync()).Select(p => resultSelector.Invoke(p)), type, parameters);
}
#endregion
#region
public static TResult ExecuteEntities2<TResult>(this dbbase db, string sqlText, Func<DataTable[], TResult> resultSelector, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => resultSelector.Invoke(cmd.FillTables()), parameters);
}
public static TResult ExecuteEntities2<TResult>(this dbbase db, string sqlText, Func<DataTable[], TResult> resultSelector, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, cmd => resultSelector.Invoke(cmd.FillTables()), type, parameters);
}
public static Task<TResult> ExecuteEntities2Async<TResult>(this dbbase db, string sqlText, Func<DataTable[], TResult> resultSelector, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, async cmd => resultSelector.Invoke(await cmd.FillTablesAsync()), parameters);
}
public static Task<TResult> ExecuteEntities2Async<TResult>(this dbbase db, string sqlText, Func<DataTable[], TResult> resultSelector, CommandType type, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, async cmd => resultSelector.Invoke(await cmd.FillTablesAsync()), type, parameters);
}
#endregion
#region
public static TResult ExecuteCommand<TResult>(this dbbase db, string sqlText, Func<SqlCommand, TResult> resultSelector, params SqlParameter[] parameters) {
return db.ExecuteCommand(sqlText, resultSelector, CommandType.Text, parameters);
}
public static TResult ExecuteCommand<TResult>(this dbbase db, string sqlText, Func<SqlCommand, TResult> resultSelector, CommandType type, params SqlParameter[] parameters) {
using (SqlConnection conn = new SqlConnection(connectionString)) {
conn.Open();
conn.ChangeDatabase(GetDataBaseName(db));
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = sqlText;
cmd.CommandType = type;
if (parameters != null && parameters.Length > 0) {
cmd.Parameters.AddRange(parameters);
}
return resultSelector.Invoke(cmd);
}
}
}
public static Task<TResult> ExecuteCommandAsync<TResult>(this dbbase db, string sqlText, Func<SqlCommand, Task<TResult>> resultSelector, params SqlParameter[] parameters) {
return db.ExecuteCommandAsync(sqlText, resultSelector, CommandType.Text, parameters);
}
public static async Task<TResult> ExecuteCommandAsync<TResult>(this dbbase db, string sqlText, Func<SqlCommand, Task<TResult>> resultSelector, CommandType type, params SqlParameter[] parameters) {
using (SqlConnection conn = new SqlConnection(connectionString)) {
await conn.OpenAsync();
conn.ChangeDatabase(GetDataBaseName(db));
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = sqlText;
cmd.CommandType = type;
if (parameters != null && parameters.Length > 0) {
cmd.Parameters.AddRange(parameters);
}
return await resultSelector.Invoke(cmd);
}
}
}
#endregion
#endregion
#region
public static TResult ExecuteTransaction<TResult>(this dbbase db, Func<SqlTransaction, TResult> transactionAction) {
return db.ExecuteTransaction(true, transactionAction);
}
public static TResult ExecuteTransaction<TResult>(this dbbase db, bool throwIfException, Func<SqlTransaction, TResult> transactionAction) {
var result = default(TResult);
using (var conn = new SqlConnection(connectionString)) {
conn.Open();
conn.ChangeDatabase(GetDataBaseName(db));
using (var transaction = conn.BeginTransaction()) {
try {
result = transactionAction.Invoke(transaction);
transaction.Commit();
} catch (Exception ex) {
Debug.Error("ExecuteTransaction " + ex);
transaction.SafeRollback();
if (throwIfException) {
throw ex;
}
}
}
}
return result;
}
public static Task<TResult> ExecuteTransactionAsync<TResult>(this dbbase db, Func<SqlTransaction, Task<TResult>> transactionAction) {
return db.ExecuteTransactionAsync(true, transactionAction);
}
public static async Task<TResult> ExecuteTransactionAsync<TResult>(this dbbase db, bool throwIfException, Func<SqlTransaction, Task<TResult>> transactionAction) {
var result = default(TResult);
using (var conn = new SqlConnection(connectionString)) {
await conn.OpenAsync();
conn.ChangeDatabase(GetDataBaseName(db));
using (var transaction = conn.BeginTransaction()) {
try {
result = await transactionAction.Invoke(transaction);
transaction.Commit();
} catch (Exception ex) {
Debug.Error("ExecuteTransaction " + ex);
transaction.SafeRollback();
if (throwIfException) {
throw ex;
}
}
}
}
return result;
}
/// <summary>
///
/// </summary>
/// <param name="transaction"></param>
/// <param name="sqlText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static TResult ExecuteQuery<TResult>(this SqlTransaction transaction, string sqlText, Func<SqlCommand, TResult> resultSelector, params SqlParameter[] parameters) {
return transaction.ExecuteQuery(sqlText, resultSelector, CommandType.Text, parameters);
}
public static TResult ExecuteQuery<TResult>(this SqlTransaction transaction, string sqlText, Func<SqlCommand, TResult> resultSelector, CommandType type, params SqlParameter[] parameters) {
using (var cmd = new SqlCommand(sqlText, transaction.Connection, transaction) { CommandType = type }) {
if (parameters != null && parameters.Length > 0) {
cmd.Parameters.AddRange(parameters);
}
var result = resultSelector.Invoke(cmd);
return result;
}
}
public static int ExecuteNonQuery(this SqlTransaction transaction, string sqlText, params SqlParameter[] parameters) {
return transaction.ExecuteNonQuery(sqlText, CommandType.Text, parameters);
}
public static int ExecuteNonQuery(this SqlTransaction transaction, string sqlText, CommandType type, params SqlParameter[] parameters) {
return transaction.ExecuteQuery(sqlText, cmd => cmd.ExecuteNonQuery(), type, parameters);
}
public static Task<int> ExecuteNonQueryAsync(this SqlTransaction transaction, string sqlText, params SqlParameter[] parameters) {
return transaction.ExecuteNonQueryAsync(sqlText, CommandType.Text, parameters);
}
public static Task<int> ExecuteNonQueryAsync(this SqlTransaction transaction, string sqlText, CommandType type, params SqlParameter[] parameters) {
return transaction.ExecuteQuery(sqlText, cmd => cmd.ExecuteNonQueryAsync(), type, parameters);
}
public static object ExecuteScalar(this SqlTransaction transaction, string sqlText, params SqlParameter[] parameters) {
return transaction.ExecuteScalar(sqlText, CommandType.Text, parameters);
}
public static object ExecuteScalar(this SqlTransaction transaction, string sqlText, CommandType type, params SqlParameter[] parameters) {
return transaction.ExecuteQuery(sqlText, cmd => cmd.ExecuteScalar(), type, parameters);
}
public static Task<object> ExecuteScalarAsync(this SqlTransaction transaction, string sqlText, params SqlParameter[] parameters) {
return transaction.ExecuteScalarAsync(sqlText, CommandType.Text, parameters);
}
public static Task<object> ExecuteScalarAsync(this SqlTransaction transaction, string sqlText, CommandType type, params SqlParameter[] parameters) {
return transaction.ExecuteQuery(sqlText, cmd => cmd.ExecuteScalarAsync(), type, parameters);
}
public static void SafeRollback(this SqlTransaction transaction) {
try {
transaction.Rollback();
} catch (Exception ex) {
Debug.Error("SafeRollback:" + ex);
}
}
#endregion
#region Common
private static string GetDataBaseName(dbbase db) {
switch (db) {
case dbbase.gamedb:
return "jnxdgame";
case dbbase.game2018:
return "game2018";
default:
throw new NotSupportedException(nameof(db));
}
}
public static DataTable FillTable(this SqlCommand cmd) {
return cmd.FillTables().FirstOrDefault() ?? new DataTable();
}
public static DataTable[] FillTables(this SqlCommand cmd) {
using (var adapter = new SqlDataAdapter(cmd)) {
using (var dataSet = new DataSet()) {
adapter.Fill(dataSet);
var tabs = new DataTable[dataSet.Tables.Count];
for (int i = 0; i < dataSet.Tables.Count; i++) {
tabs[i] = dataSet.Tables[i];
}
return tabs;
}
}
}
public static async Task<DataTable> FillTableAsync(this SqlCommand cmd) {
using (var reader = await cmd.ExecuteReaderAsync()) {
return await reader.FillTableInternal();
}
}
public static async Task<DataTable[]> FillTablesAsync(this SqlCommand cmd) {
using (var reader = await cmd.ExecuteReaderAsync()) {
var tables = new Collection<DataTable>();
do {
var datatable = await reader.FillTableInternal();
if (datatable != null) {
tables.Add(datatable);
}
} while (await reader.NextResultAsync());
return tables.ToArray();
}
}
static async Task<DataTable> FillTableInternal(this SqlDataReader reader) {
var datatable = new DataTable();
if (reader.FieldCount > 0) {
datatable.Columns.AddRange(Enumerable.Range(0, reader.FieldCount)
.Select(i => new DataColumn(reader.GetName(i), reader.GetFieldType(i)))
.ToArray());
///添加行数据
while (await reader.ReadAsync()) {
var myDataRow = datatable.NewRow();
for (int i = 0; i < reader.FieldCount; i++) {
myDataRow[i] = reader[i];
}
datatable.Rows.Add(myDataRow);
}
}
return datatable;
}
#endregion
#endregion
}