using Dapper; using DotNetNuke.Instrumentation; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using <%= fullNamespace %>.Constants; using static Dapper.SqlMapper; using <%= fullNamespace %>.Data; using <%= fullNamespace %>.Repository.Contract; namespace <%= fullNamespace %>.Repository { public class GenericRepository : IGenericRepository where T : class { private readonly IDbConnection _connection; private readonly ILog _logger; public GenericRepository(DapperContext context) { _connection = context.CreateConnection(); _logger = LoggerSource.Instance.GetLogger(GetType()); } /// /// Adds a new entity of type T to the database. /// /// The entity to add to the database. /// /// true if the entity was successfully added; otherwise, false. /// public async Task AddAsync(T entity) { int rowsEffected = 0; try { // Get the name of the table associated with the entity type. string tableName = GetTableName(); // Get the names of columns and properties, excluding the primary key. string columns = GetColumns(excludeKey: true); string properties = GetPropertyNames(excludeKey: true); // Create an SQL query to insert the entity into the table. string query = $"INSERT INTO {tableName} ({columns}) VALUES ({properties})"; // Execute the insert query asynchronously, specifying the entity as parameters. rowsEffected = await _connection.ExecuteAsync(query, entity); } catch (Exception ex) { _logger.Error(ex); } // Return true if at least one row is affected by the insert; otherwise, return false. return rowsEffected > 0 ? true : false; } /// /// Deletes an entity of type T from the database based on its primary key. /// /// The entity to delete from the database. /// /// true if the entity was successfully deleted; otherwise, false. /// public async Task DeleteAsync(T entity) { int rowsEffected = 0; try { // Get the name of the table associated with the entity type. string tableName = GetTableName(); // Get the name of the primary key column and property. string keyColumn = GetKeyColumnName(); string keyProperty = GetKeyPropertyName(); // Create an SQL query to delete the entity based on its primary key. string query = $"DELETE FROM {tableName} WHERE {keyColumn} = @{keyProperty}"; // Execute the delete query asynchronously, specifying the entity as parameters. rowsEffected = await _connection.ExecuteAsync(query, entity); } catch (Exception ex) { _logger.Error(ex); } // Return true if at least one row is affected by the delete; otherwise, return false. return rowsEffected > 0 ? true : false; } /// /// Retrieves all entities of type T from the database. /// /// /// A collection of all entities of type T found in the database. /// public async Task> GetAllAsync() { IEnumerable result = null; try { // Get the name of the table associated with the entity type. string tableName = GetTableName(); // Construct an SQL query to select all records from the table. string query = $"SELECT * FROM {tableName}"; // Execute the query asynchronously and retrieve the results into a collection. result = await _connection.QueryAsync(query); } catch (Exception ex) { _logger.Error(ex); } // Return a collection containing all entities of type T found in the database. return result; } /// /// Retrieves an entity of type T from the database by its unique identifier. /// /// The unique identifier of the entity to retrieve. /// /// The entity of type T with the specified unique identifier, or null if not found. /// public async Task GetByIdAsync(int Id) { IEnumerable result = null; try { // Get the name of the table associated with the entity type. string tableName = GetTableName(); // Get the name of the primary key column for the entity. string keyColumn = GetKeyColumnName(); // Construct an SQL query to select the entity by its primary key. string query = $"SELECT * FROM {tableName} WHERE {keyColumn} = @Id"; // Execute the query asynchronously with the provided Id parameter. result = await _connection.QueryAsync(query, new { Id }); } catch (Exception ex) { _logger.Error(ex); } // Return the first entity found with the specified Id, or null if not found. return result.FirstOrDefault(); } /// /// Updates an entity of type T in the database with the provided data. /// /// The entity to update in the database. /// /// A boolean indicating whether the update operation was successful (true) or not (false). /// public async Task UpdateAsync(T entity) { int rowsEffected = 0; try { // Get the name of the table associated with the entity type. string tableName = GetTableName(); // Get the name of the primary key column for the entity. string keyColumn = GetKeyColumnName(); // Get the name of the primary key property for the entity. string keyProperty = GetKeyPropertyName(); // Initialize a StringBuilder to construct the SQL update query. StringBuilder query = new StringBuilder(); query.Append($"UPDATE {tableName} SET "); // Iterate through the entity properties. foreach (var property in GetProperties(true)) { var columnAttr = property.GetCustomAttribute(); string propertyName = property.Name; string columnName = columnAttr.Name; // Append each property assignment in the update query. query.Append($"{columnName} = @{propertyName},"); } // Remove the trailing comma from the query. query.Remove(query.Length - 1, 1); // Append the WHERE clause to identify the entity to update by its primary key. query.Append($" WHERE {keyColumn} = @{keyProperty}"); // Execute the update query asynchronously with the provided entity data. rowsEffected = await _connection.ExecuteAsync(query.ToString(), entity); } catch (Exception ex) { _logger.Error(ex); } // Return true if at least one row is affected by the update; otherwise, return false. return rowsEffected > 0 ? true : false; } /// /// Gets the name of the database table associated with the entity type T. /// /// /// The name of the database table for the entity type T. /// public string GetTableName() { string tableName = string.Empty; var type = typeof(T); // Attempt to retrieve the TableAttribute for the entity type. var tableAttr = type.GetCustomAttribute(); if (tableAttr != null) { // If a TableAttribute is found, use its specified table name. tableName = tableAttr.Name; return tableName; } // If no TableAttribute is found, generate a table name using a naming convention. // The convention is based on appending "_s" to the entity type's name, optionally with a prefix. return $"{ModuleConstants.DBTABLE_PREFIX}_{type.Name}" + "s"; } /// /// Gets the name of the primary key column associated with the entity type T. /// /// /// The name of the primary key column for the entity type T, or null if not found. /// public static string GetKeyColumnName() { // Retrieve all properties of the entity type T. PropertyInfo[] properties = typeof(T).GetProperties(); foreach (PropertyInfo property in properties) { // Check if the property has a KeyAttribute applied. object[] keyAttributes = property.GetCustomAttributes(typeof(KeyAttribute), true); if (keyAttributes != null && keyAttributes.Length > 0) { // If the property has a KeyAttribute, check if it also has a ColumnAttribute applied. object[] columnAttributes = property.GetCustomAttributes(typeof(ColumnAttribute), true); if (columnAttributes != null && columnAttributes.Length > 0) { // If a ColumnAttribute is found, retrieve its Name property as the key column name. ColumnAttribute columnAttribute = (ColumnAttribute)columnAttributes[0]; return columnAttribute.Name; } else { // If no ColumnAttribute is found, use the property name as the key column name. return property.Name; } } } // Return null if no property with a KeyAttribute is found. return null; } /// /// Gets a comma-separated string of column names for the entity type T. /// /// Whether to exclude columns marked as primary keys. /// /// A string containing comma-separated column names for the entity type T. /// private string GetColumns(bool excludeKey = false) { var type = typeof(T); // Use LINQ to query and construct the column names. var columns = string.Join(", ", type.GetProperties() .Where(p => !excludeKey || !p.IsDefined(typeof(KeyAttribute))) // Optionally exclude primary key columns. .Select(p => { var columnAttr = p.GetCustomAttribute(); return columnAttr != null ? columnAttr.Name : p.Name; // Use custom column name if specified via ColumnAttribute. })); return columns; } /// /// Gets a comma-separated string of parameter names for the entity type T. /// /// Whether to exclude properties marked as primary keys. /// /// A string containing comma-separated parameter names for the entity type T. /// protected string GetPropertyNames(bool excludeKey = false) { var properties = typeof(T).GetProperties() .Where(p => !excludeKey || p.GetCustomAttribute() == null); var values = string.Join(", ", properties.Select(p => { return $"@{p.Name}"; })); return values; } /// /// Gets a collection of PropertyInfo objects representing the properties of the entity type T. /// /// Whether to exclude properties marked as primary keys. /// /// A collection of PropertyInfo objects representing the properties of the entity type T. /// protected IEnumerable GetProperties(bool excludeKey = false) { var properties = typeof(T).GetProperties() .Where(p => !excludeKey || p.GetCustomAttribute() == null); return properties; } /// /// Gets the name of the property that is marked as the primary key for the entity type T. /// /// /// The name of the primary key property or null if no primary key is defined. /// protected string GetKeyPropertyName() { var properties = typeof(T).GetProperties() .Where(p => p.GetCustomAttribute() != null); if (properties.Any()) { return properties.FirstOrDefault().Name; } return null; } } }