diff --git a/src/Comparer/PropertyEqualityComparer.cs b/src/Comparer/PropertyEqualityComparer.cs new file mode 100644 index 0000000..e39e29d --- /dev/null +++ b/src/Comparer/PropertyEqualityComparer.cs @@ -0,0 +1,58 @@ +using System.Reflection; + +namespace DbSyncKit.DB.Comparer +{ + /// + /// Compares instances of data contracts based on specified properties, which can be either key or comparable properties. + /// + public class PropertyEqualityComparer : IEqualityComparer + { + /// + /// Gets the array of objects representing properties used for equality comparison. + /// These properties can serve as either key or comparable properties. + /// + public readonly PropertyInfo[] properties; + + /// + /// Initializes a new instance of the class. + /// + /// An array of objects representing properties used for equality comparison. These can be either key or comparable properties. + public PropertyEqualityComparer(PropertyInfo[] Properties) + { + properties = Properties; + } + + /// + /// Determines whether two instances of the data contract are equal based on the specified properties. + /// + /// The first instance to compare. + /// The second instance to compare. + /// true if the instances are equal; otherwise, false. + public bool Equals(T? x, T? y) + { + return properties.All(prop => Equals(prop.GetValue(x), prop.GetValue(y))); + } + + /// + /// Returns a hash code for the specified instance of the data contract based on the specified properties. + /// + /// The instance for which to get the hash code. + /// A hash code for the specified instance. + public int GetHashCode(T obj) + { + unchecked + { + int hash = 17; + + foreach (var prop in properties) + { + var value = prop.GetValue(obj); + hash = hash ^ ((value?.GetHashCode() ?? 0) + 23); + } + + return hash; + } + } + } + +} diff --git a/src/DatabaseManager.cs b/src/DatabaseManager.cs index 92a2d04..afe7067 100644 --- a/src/DatabaseManager.cs +++ b/src/DatabaseManager.cs @@ -28,7 +28,7 @@ public DatabaseManager(T databaseProvider) /// The SQL query to execute. /// The name of the table associated with the query. /// A list of results of type . - public List ExecuteQuery(string query, string tableName) where TItem : IDataContract + public List ExecuteQuery(string query, string tableName) { List result = new List(); diff --git a/src/DbSyncKit.DB.csproj b/src/DbSyncKit.DB.csproj index 4e1305c..afd1d9c 100644 --- a/src/DbSyncKit.DB.csproj +++ b/src/DbSyncKit.DB.csproj @@ -5,9 +5,9 @@ enable enable True - 1.2.0.0 - 1.2.0.0 - 1.2.0.0 + 1.3.0.0 + 1.3.0.0 + 1.3.0.0 README.md https://dbsynckit.rohit-mahajan.in/ https://github.com/RohitM-IN/DbSyncKit @@ -31,4 +31,8 @@ + + + + diff --git a/src/Extensions/DataRowExtensions.cs b/src/Extensions/DataRowExtensions.cs index 03401fe..efb4499 100644 --- a/src/Extensions/DataRowExtensions.cs +++ b/src/Extensions/DataRowExtensions.cs @@ -14,9 +14,6 @@ public static class DataRowExtensions /// The DataRow from which to retrieve the value. /// The name of the column. /// The value of the specified column, converted to the specified type. - /// - /// This extension method is intended for use with classes that inherit from . - /// public static T GetValue(this DataRow row, string columnName) { // Check if the DataRow is null diff --git a/src/Factory/QueryGeneratorFactory.cs b/src/Factory/QueryGeneratorFactory.cs index f8a0bc9..c20f012 100644 --- a/src/Factory/QueryGeneratorFactory.cs +++ b/src/Factory/QueryGeneratorFactory.cs @@ -1,5 +1,6 @@ using DbSyncKit.DB.Enum; using DbSyncKit.DB.Interface; +using DbSyncKit.Templates.Interface; using System; using System.Collections.Generic; using System.Linq; diff --git a/src/Fetcher/DataContractFetcher.cs b/src/Fetcher/DataContractFetcher.cs new file mode 100644 index 0000000..516be8e --- /dev/null +++ b/src/Fetcher/DataContractFetcher.cs @@ -0,0 +1,144 @@ +using DbSyncKit.DB.Comparer; +using DbSyncKit.DB.Factory; +using DbSyncKit.DB.Interface; +using DbSyncKit.Templates; +using DbSyncKit.Templates.Interface; + +namespace DbSyncKit.DB.Fetcher +{ + /// + /// Represents a callback function for filtering a list of data entities of type T. + /// + /// The type of data entities to filter. + /// The list of data entities to filter. + /// A filtered list of data entities. + /// + /// This delegate defines a callback function that takes a list of data entities as input, + /// performs filtering operations on the data, and returns the filtered list. + /// + public delegate List FilterCallback(List data); + + /// + /// Utility class for fetching data from a database using data contracts. + /// + public class DataContractFetcher + { + #region Properties + + /// + /// Gets the query generator factory instance used for creating query generators. + /// + private readonly QueryGeneratorFactory Factory; + + /// + /// Gets or sets the QueryGenerationManager instance for generating queries for the destination database. + /// + /// + /// This property is set by the method. + /// It allows the reuse of the QueryGenerationManager instance when the source and destination databases share the same provider. + /// + public IQueryGenerator? DestinationQueryGenerationManager { get; private set; } + + #endregion + + #region Constructor + + /// + /// Initializes a new instance of the class with a custom query generator factory. + /// + /// The custom query generator factory instance. + public DataContractFetcher(QueryGeneratorFactory factory) + { + Factory = factory; + } + + #endregion + + #region Methods + + /// + /// Retrieves data from source and destination databases for a specified table and column list, using a specified data contract type. + /// + /// The type of data entities to retrieve. + /// The source database. + /// The destination database. + /// The name of the table from which to retrieve data. + /// A list of column names to retrieve from the table. + /// An equality comparer for identifying properties used in data comparison. + /// A callback function for filtering the retrieved data. + /// An output parameter that receives the retrieved data from the source database. + /// An output parameter that receives the retrieved data from the destination database. + /// + /// The method uses a QueryGenerationManager to generate queries for retrieving data based on the specified table and columns. + /// If the providers of the source and destination databases differ, a new QueryGenerationManager is created for the destination database. + /// The retrieved data can be optionally filtered using the provided filter callback function. + /// + public void RetrieveDataFromDatabases( + IDatabase source, + IDatabase destination, + string tableName, + List ColumnList, + PropertyEqualityComparer ComparablePropertyEqualityComparer, + FilterCallback? filterCallback, + out HashSet sourceList, + out HashSet destinationList) + { + var sourceQueryGenerationManager = new QueryGenerationManager(Factory.GetQueryGenerator(source.Provider)); + sourceList = GetDataFromDatabase(tableName, source, sourceQueryGenerationManager, ColumnList, ComparablePropertyEqualityComparer, filterCallback); + + if (source.Provider != destination.Provider) + { + sourceQueryGenerationManager.Dispose(); + DestinationQueryGenerationManager = new QueryGenerationManager(Factory.GetQueryGenerator(destination.Provider)); + } + else + { + DestinationQueryGenerationManager = sourceQueryGenerationManager; + } + + destinationList = GetDataFromDatabase(tableName, destination, DestinationQueryGenerationManager, ColumnList, ComparablePropertyEqualityComparer, filterCallback); + } + + /// + /// Retrieves data from a database for a specified table, columns, and data contract type. + /// + /// The type of data entities to retrieve. + /// The name of the table from which to retrieve data. + /// The database connection. + /// The query generation manager for creating the SELECT query. + /// A list of column names to retrieve from the table. + /// An equality comparer for identifying properties used in data comparison. + /// A callback function for filtering the retrieved data. + /// + /// A HashSet of data entities of type T retrieved from the specified table and columns in the database. + /// + /// + /// The method generates a SELECT query using the provided query generation manager and executes it using a DatabaseManager. + /// The resulting data is converted to a HashSet using the specified property equality comparer for data comparison. + /// The retrieved data can be optionally filtered using the provided filter callback function. + /// + public HashSet GetDataFromDatabase( + string tableName, + IDatabase connection, + IQueryGenerator manager, + List columns, + PropertyEqualityComparer ComparablePropertyEqualityComparer, + FilterCallback? filterCallback) + { + var query = manager.GenerateSelectQuery(tableName, columns, string.Empty); + + using var DBManager = new DatabaseManager(connection); + + var data = DBManager.ExecuteQuery(query, tableName); + + if (filterCallback != null) + { + data = filterCallback(data); + } + + return data.ToHashSet(ComparablePropertyEqualityComparer); + } + + #endregion + } +} diff --git a/src/Helper/QueryHelper.cs b/src/Helper/QueryHelper.cs index 186e395..6bff04e 100644 --- a/src/Helper/QueryHelper.cs +++ b/src/Helper/QueryHelper.cs @@ -12,9 +12,9 @@ public class QueryHelper /// /// Gets the table name of a specified type, considering the TableNameAttribute if present. /// - /// The type for which to get the table name. Must implement . + /// The type for which to get the table name. /// The table name. - public string GetTableName() where T : IDataContract + public string GetTableName() { return CacheManager.GetTableName(typeof(T)); } @@ -22,9 +22,9 @@ public string GetTableName() where T : IDataContract /// /// Gets the table schema of a specified type, considering the TableSchemaAttribute if present. /// - /// The type for which to get the table schema. Must implement . + /// The type for which to get the table schema. /// The table schema name or null if not specified. - public string? GetTableSchema() where T : IDataContract + public string? GetTableSchema() { return CacheManager.GetTableSchema(typeof(T)); } @@ -32,9 +32,9 @@ public string GetTableName() where T : IDataContract /// /// Gets whether the type specifies to generate an INSERT query with ID, considering the GenerateInsertWithIDAttribute if present. /// - /// The type for which to determine the generation of INSERT query with ID. Must implement . + /// The type for which to determine the generation of INSERT query with ID. /// True if the INSERT query should include ID, otherwise false. - public bool GetInsertWithID() where T : IDataContract + public bool GetInsertWithID() { return CacheManager.GetInsertWithID(typeof(T)); } @@ -44,9 +44,9 @@ public bool GetInsertWithID() where T : IDataContract /// during insert query generation, considering the GenerateInsertWithIDAttribute if present. /// /// The type for which to determine the inclusion of identity insert statements. - /// Must implement . + /// /// true if identity insert statements should be included; otherwise, false. - public bool GetIncludeIdentityInsert() where T : IDataContract + public bool GetIncludeIdentityInsert() { return CacheManager.GetIncludeIdentityInsert(typeof(T)); } @@ -54,10 +54,9 @@ public bool GetIncludeIdentityInsert() where T : IDataContract /// /// Gets the names of properties marked as key columns for a specified type. /// - /// The type for which to get the key columns. Must implement . + /// The type for which to get the key columns. /// A list of key column names. - /// - public List GetKeyColumns() where T : IDataContract + public List GetKeyColumns() { return CacheManager.GetKeyColumns(typeof(T)); } @@ -65,10 +64,9 @@ public List GetKeyColumns() where T : IDataContract /// /// Gets the names of properties marked as excluded properties for a specified type. /// - /// The type for which to get the excluded properties. Must implement . + /// The type for which to get the excluded properties. /// A list of excluded property names. - /// - public List GetExcludedColumns() where T : IDataContract + public List GetExcludedColumns() { return CacheManager.GetExcludedColumns(typeof(T)); } @@ -76,10 +74,9 @@ public List GetExcludedColumns() where T : IDataContract /// /// Gets the names of all properties for a specified type. /// - /// The type for which to get all properties. Must implement . + /// The type for which to get all properties. /// A list of all property names. - /// - public List GetAllColumns() where T : IDataContract + public List GetAllColumns() { return CacheManager.GetAllColumns(typeof(T)); } @@ -87,37 +84,33 @@ public List GetAllColumns() where T : IDataContract /// /// Retrieves a list of identity columns for a specified data contract type . /// - /// The type implementing the IDataContract interface. /// A list containing the names of identity columns for the specified data contract type . /// /// This method uses reflection to analyze the properties of the specified type and retrieves properties marked with a [Key] attribute, indicating identity columns. /// - /// - public List GetIdentityColumns() where T : IDataContract + public List GetIdentityColumns() { return CacheManager.GetIdentityColumns(typeof(T)); } /// /// Retrieves an array of objects representing the properties that are used for data comparison - /// in objects of type . These properties are determined based on the implementation of the - /// interface. + /// in objects of type . /// /// The type of objects for which to retrieve comparable properties. /// An array of objects representing the comparable properties of type . - public PropertyInfo[] GetComparableProperties() where T: IDataContract + public PropertyInfo[] GetComparableProperties() { return CacheManager.GetComparableProperties(typeof(T)); } /// /// Retrieves an array of objects representing the properties that are used as key properties - /// for uniquely identifying objects of type . These key properties are determined based on the - /// implementation of the interface. + /// for uniquely identifying objects of type . /// /// The type of objects for which to retrieve key properties. /// An array of objects representing the key properties of type . - public PropertyInfo[] GetKeyProperties() where T : IDataContract + public PropertyInfo[] GetKeyProperties() { return CacheManager.GetKeyProperties(typeof(T)); } diff --git a/src/Interface/IDataContract.cs b/src/Interface/IDataContract.cs deleted file mode 100644 index 38e17e7..0000000 --- a/src/Interface/IDataContract.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace DbSyncKit.DB.Interface -{ - /// - /// Represents an interface for data contracts that require comparison functionality. - /// - /// - /// Implement this interface in data contracts to enable comparison functionality. - /// - public interface IDataContract - { - } -} diff --git a/src/Interface/IQueryGenerator.cs b/src/Interface/IQueryGenerator.cs deleted file mode 100644 index b400392..0000000 --- a/src/Interface/IQueryGenerator.cs +++ /dev/null @@ -1,84 +0,0 @@ -namespace DbSyncKit.DB.Interface -{ - /// - /// Defines methods for generating SQL queries and handling query-related operations. - /// - public interface IQueryGenerator : IDisposable - { - /// - /// Generates a SELECT query for retrieving data from a database table. - /// - /// The type of entity that implements IDataContract. - /// The name of the database table. - /// The list of columns to be selected. - /// The schema name of the database table. - /// A string representing the generated SELECT query. - string GenerateSelectQuery(string tableName, List ListOfColumns, string schemaName) where T : IDataContract; - - /// - /// Generates an UPDATE query for updating data in a database table. - /// - /// The type of entity that implements IDataContract. - /// The entity with the updated data. - /// The list of key columns used for updating. - /// The list of columns to be excluded from the update. - /// A dictionary representing the properties and their new values to be updated. - /// A string representing the generated UPDATE query. - string GenerateUpdateQuery(T DataContract, List keyColumns, List excludedColumns, (string propName, object propValue)[] editedProperties) where T : IDataContract; - - /// - /// Generates a DELETE query for deleting data from a database table. - /// - /// The type of entity that implements IDataContract. - /// The entity representing the data to be deleted. - /// The list of key columns used for deletion. - /// A string representing the generated DELETE query. - string GenerateDeleteQuery(T entity, List keyColumns) where T : IDataContract; - - /// - /// Generates an INSERT query for inserting data into a database table. - /// - /// The type of entity that implements IDataContract. - /// The entity representing the data to be inserted. - /// The list of key columns used for insertion. - /// The list of columns to be excluded from the insertion. - /// A string representing the generated INSERT query. - string GenerateInsertQuery(T entity, List keyColumns, List excludedColumns) where T : IDataContract; - - /// - /// Generates a SQL comment. - /// - /// The comment text. - /// A string representing the generated comment. - string GenerateComment(string comment); - - /// - /// Gets a condition for use in a SQL WHERE clause based on the entity and key columns. - /// - /// The type of entity that implements IDataContract. - /// The entity for which the condition is generated. - /// The list of key columns used to create the condition. - /// A string representing the generated condition for a SQL WHERE clause. - List GetCondition(T entity, List keyColumns) where T : IDataContract; - - /// - /// Escapes special characters in the input to make it SQL-safe. - /// - /// The input object or string to be escaped. - /// The escaped object or string. - object? EscapeValue(object? input); - - /// - /// Escapes the input column name to be used safely in SQL queries. - /// - /// The input column name to be escaped. - /// The escaped column name. - string EscapeColumn(string? input); - - /// - /// Generates a SQL batch separator ('GO' statement in SQL Server) used to execute batches of SQL statements. - /// - /// A string representing the generated batch separator. - string GenerateBatchSeparator(); - } -} diff --git a/src/QueryGenerationManager.cs b/src/QueryGenerationManager.cs deleted file mode 100644 index 9f354e8..0000000 --- a/src/QueryGenerationManager.cs +++ /dev/null @@ -1,88 +0,0 @@ -using DbSyncKit.DB.Interface; - -namespace DbSyncKit.DB -{ - /// - /// Manages the generation of SQL queries for data operations by delegating the query generation tasks - /// to an implementation of the interface. - /// - /// - /// This class acts as a wrapper around an instance of and forwards - /// query generation requests to the underlying implementation. - /// - public class QueryGenerationManager : IQueryGenerator - { - private readonly IQueryGenerator _querryGenerator; - - /// - /// The underlying query generator instance used for actual query generation. - /// - public QueryGenerationManager(IQueryGenerator querryGenerator) - { - _querryGenerator = querryGenerator; - } - - #region Public Methods - /// - public string GenerateSelectQuery(string tableName, List listOfColumns, string schemaName) where T : IDataContract - { - return _querryGenerator.GenerateSelectQuery(tableName, listOfColumns, schemaName); - } - - /// - public string GenerateUpdateQuery(T DataContract, List keyColumns, List excludedColumns, (string propName, object propValue)[] editedProperties) where T : IDataContract - { - return _querryGenerator.GenerateUpdateQuery(DataContract, keyColumns, excludedColumns, editedProperties); - } - - /// - public string GenerateDeleteQuery(T entity, List keyColumns) where T : IDataContract - { - return _querryGenerator.GenerateDeleteQuery(entity, keyColumns); - } - - /// - public string GenerateInsertQuery(T entity, List keyColumns, List excludedColumns) where T : IDataContract - { - return _querryGenerator.GenerateInsertQuery(entity, keyColumns, excludedColumns); - } - - /// - public string GenerateComment(string comment) - { - return _querryGenerator.GenerateComment(comment); - } - - /// - public List GetCondition(T entity, List keyColumns) where T : IDataContract - { - return _querryGenerator.GetCondition(entity, keyColumns); - } - - /// - public object? EscapeValue(object? input) - { - return _querryGenerator.EscapeValue(input); - } - - /// - public string EscapeColumn(string? input) - { - return _querryGenerator.EscapeColumn(input); - } - - /// - public string GenerateBatchSeparator() - { - return _querryGenerator.GenerateBatchSeparator(); - } - - /// - public void Dispose() - { - _querryGenerator.Dispose(); - } - - #endregion - } -}