실행환경검사 invoke 오류 수정

This commit is contained in:
ChiKyun Kim
2025-07-29 08:38:21 +09:00
parent e309864262
commit c0eb33f60a
22 changed files with 773 additions and 209 deletions

View File

@@ -6,6 +6,7 @@ using System.Data.SqlClient;
using System.Windows.Forms;
using FCOMMON.Models;
using System.Data;
using System.Reflection;
namespace FCOMMON
{
@@ -1801,5 +1802,218 @@ namespace FCOMMON
cn2.Dispose();
return retval;
}
#region Generic Query Methods
/// <summary>
/// Generic Query method that returns a list of objects of type T
/// </summary>
/// <typeparam name="T">The type to map the results to</typeparam>
/// <param name="sql">SQL query string</param>
/// <param name="parameters">Anonymous object containing parameters</param>
/// <returns>List of objects of type T</returns>
public static List<T> Query<T>(string sql, object parameters = null) where T : new()
{
var retval = new List<T>();
var cn = getCn();
try
{
cn.Open();
var cmd = new SqlCommand(sql, cn);
// Add parameters if provided
if (parameters != null)
{
AddParameters(cmd, parameters);
}
var rdr = cmd.ExecuteReader();
while (rdr.Read())
{
var item = MapReaderToObject<T>(rdr);
retval.Add(item);
}
rdr.Close();
cmd.Dispose();
}
catch (Exception ex)
{
// Log error if needed
throw new Exception($"Query<{typeof(T).Name}> failed: {ex.Message}", ex);
}
finally
{
cn.Close();
cn.Dispose();
}
return retval;
}
/// <summary>
/// Generic QuerySingle method that returns a single object of type T
/// </summary>
/// <typeparam name="T">The type to map the result to</typeparam>
/// <param name="sql">SQL query string</param>
/// <param name="parameters">Anonymous object containing parameters</param>
/// <returns>Single object of type T</returns>
/// <exception cref="InvalidOperationException">Thrown when no data is found or more than one row is returned</exception>
public static T QuerySingle<T>(string sql, object parameters = null) where T : new()
{
var results = Query<T>(sql, parameters);
if (results.Count == 0)
throw new InvalidOperationException("Sequence contains no elements");
if (results.Count > 1)
throw new InvalidOperationException("Sequence contains more than one element");
return results.First();
}
/// <summary>
/// Generic QuerySingleOrDefault method that returns a single object of type T or default value
/// </summary>
/// <typeparam name="T">The type to map the result to</typeparam>
/// <param name="sql">SQL query string</param>
/// <param name="parameters">Anonymous object containing parameters</param>
/// <returns>Single object of type T or default value if no data found</returns>
/// <exception cref="InvalidOperationException">Thrown when more than one row is returned</exception>
public static T QuerySingleOrDefault<T>(string sql, object parameters = null) where T : new()
{
var results = Query<T>(sql, parameters);
if (results.Count == 0)
return default(T);
if (results.Count > 1)
throw new InvalidOperationException("Sequence contains more than one element");
return results.First();
}
/// <summary>
/// Execute a command with parameters and return the number of affected rows
/// </summary>
/// <param name="sql">SQL command string</param>
/// <param name="parameters">Anonymous object containing parameters</param>
/// <returns>Number of affected rows</returns>
public static int Execute(string sql, object parameters = null)
{
var cn = getCn();
int retval = 0;
try
{
cn.Open();
var cmd = new SqlCommand(sql, cn);
// Add parameters if provided
if (parameters != null)
{
AddParameters(cmd, parameters);
}
retval = cmd.ExecuteNonQuery();
cmd.Dispose();
}
catch (Exception ex)
{
throw new Exception($"Execute failed: {ex.Message}", ex);
}
finally
{
cn.Close();
cn.Dispose();
}
return retval;
}
/// <summary>
/// Helper method to add parameters from an anonymous object to a SqlCommand
/// </summary>
/// <param name="cmd">SqlCommand to add parameters to</param>
/// <param name="parameters">Anonymous object containing parameters</param>
private static void AddParameters(SqlCommand cmd, object parameters)
{
if (parameters == null) return;
var properties = parameters.GetType().GetProperties();
foreach (var prop in properties)
{
var value = prop.GetValue(parameters, null) ?? DBNull.Value;
cmd.Parameters.AddWithValue("@" + prop.Name, value);
}
}
/// <summary>
/// Helper method to map a SqlDataReader to an object of type T
/// </summary>
/// <typeparam name="T">The type to map to</typeparam>
/// <param name="reader">SqlDataReader containing the data</param>
/// <returns>Object of type T with mapped values</returns>
private static T MapReaderToObject<T>(SqlDataReader reader) where T : new()
{
var obj = new T();
var type = typeof(T);
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in properties)
{
// Check if the property has a setter
if (!prop.CanWrite) continue;
// Try to find a column with the same name (case insensitive)
var columnName = FindColumnName(reader, prop.Name);
if (columnName == null) continue;
var value = reader[columnName];
if (value == DBNull.Value) continue;
// Convert the value to the property type if needed
try
{
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// Handle nullable types
var underlyingType = Nullable.GetUnderlyingType(prop.PropertyType);
var convertedValue = Convert.ChangeType(value, underlyingType);
prop.SetValue(obj, convertedValue, null);
}
else
{
var convertedValue = Convert.ChangeType(value, prop.PropertyType);
prop.SetValue(obj, convertedValue, null);
}
}
catch
{
// If conversion fails, skip this property
}
}
return obj;
}
/// <summary>
/// Helper method to find a column name in the reader (case insensitive)
/// </summary>
/// <param name="reader">SqlDataReader to search in</param>
/// <param name="propertyName">Property name to find</param>
/// <returns>Column name if found, null otherwise</returns>
private static string FindColumnName(SqlDataReader reader, string propertyName)
{
for (int i = 0; i < reader.FieldCount; i++)
{
var columnName = reader.GetName(i);
if (string.Equals(columnName, propertyName, StringComparison.OrdinalIgnoreCase))
{
return columnName;
}
}
return null;
}
#endregion
}
}