/// <summary> /// Parse through the selected tables columns and check if the modified on column exists /// </summary> /// <param name="tableName">name of the table</param> /// <param name="metadataAccess">current instance of the meta data access layer</param> /// <returns>true if the table has hte ModifiedOn column</returns> private bool CheckForLastModifiedColumnName(string tableName, OleDbMetadataAccess metadataAccess) { bool hasModifiedOn = false; //get the list of column definitions DataTable columnList = metadataAccess.GetColumnDefinitions(tableName); //parse through the list of column definitions to check if the ModifiedOn column exists foreach (DataRow columnDefinition in columnList.Rows) { if (columnDefinition["COLUMN_NAME"].ToString() == LastModifiedFieldName) { hasModifiedOn = true; break; } } return hasModifiedOn; }
/// <summary> /// Get the list of primary key names in the table /// </summary> /// <param name="tableName"></param> /// <param name="metadataAccess"></param> /// <returns>LIst of primary keys for the specified table</returns> private List<string> GetTablePrimaryKeys(string tableName, OleDbMetadataAccess metadataAccess) { List<string> primaryKeys = new List<string>(); //get the list of indexes for the table DataTable indexList = metadataAccess.GetTableIndexInformation(tableName); //check that the table even has an index if (indexList != null && indexList.Rows.Count != 0) { //find the primary key values and add them to the list foreach (DataRow index in indexList.Rows) { if (Convert.ToBoolean(index["PRIMARY_KEY"])) { primaryKeys.Add(index["COLUMN_NAME"].ToString()); } } } return primaryKeys; }
/// <summary> /// This is the method to get data for replication /// for an individual object. Rows will be returned as they are read. /// </summary> /// <param name="methodInput"></param> /// <returns></returns> public MethodResult GetReplicationData(MethodInput methodInput) { MethodResult result = null; using (new LogMethodExecution( Globals.ConnectorName, "GetReplicationData")) { //Get the name of the object in the input properties. string objectName = GetPropertyValueName( "ObjectName",methodInput.Input.Properties); //Get the last sychronization date from the input properties DateTime lastSyncDate = GetLastSyncDate(methodInput.Input.Properties); OleDbMetadataAccess metadataAccess = new OleDbMetadataAccess(_dataAccess); bool hasLastModified = CheckForLastModifiedColumnName(objectName, metadataAccess); try { //Passes control of the lower level method in the data access layer //to the calling method.This passes the IEnumerable object //(filled with data rows) out to the calling methodin conjunction //with the yield statement at the lower level, is looking for the //foreach loop else control is passed out to the calling method. //Here, the attempt to get an entity is performed (by calling the //empty foreach loop) in order to check for errors - else the top //level has control and exceptions get passed directly up. Here we assume //that no error on retrieving row 1 means we are safe to pass control //back to the calling method and skip the error checking //that is forced on the first entity. IEnumerable<DataEntity> replicationData = _dataAccess.GetReplicationDataRetrieve( objectName, lastSyncDate, hasLastModified); //Force a check for errors. The previous method call //will not be performed until it is requested for use here. foreach (var dataEntity in replicationData) { break; } //Create a new method result result = new MethodResult(); //Indicate that the result is a success result.Success = true; //Set the result return to a new data entity //which MUST be named "ReplicationQueryData" result.Return = new DataEntity("ReplicationQueryData"); //Add the yielded replication data to the return properties in the result //Note: the property name MUST be labeled as 'EntityData' result.Return.Properties.Add("EntityData", replicationData); } catch (Exception exception) { //Be sure to log any errors and add them to the //error information for the method result Logger.Write( Logger.Severity.Error, Globals.ConnectorName, exception.Message); result = SetErrorMethodResult( ErrorCodes.GetData.Number, ErrorCodes.GetData.Description); } } //Return the method result containing the replication data return result; }
/// <summary> /// Get the list of 'Object' names or in this case /// table names from the data source /// include the primary key or identifyer in the each of the objects /// </summary> /// <returns>MethodResult to be return in a readable state</returns> public MethodResult GetObjectDefinitionList() { //Create a new instance of the method result to fill with //meta data information MethodResult result = new MethodResult(); // Create a new instance of the metadata access class and pass // the data access instance along with it OleDbMetadataAccess metadataAccess = new OleDbMetadataAccess(_dataAccess); // Use LogMethodExecution to add entry and exit tracing to a method. // When wrapped in a using statement, the exit point // is written during garbage collection. using (new LogMethodExecution( Globals.ConnectorName, "GetObjectDefinitionList")) { //Get a list of indexes for each table DataTable tableList = metadataAccess.GetTableList(); //check that valid data has been return from the schema if (tableList != null && tableList.Rows.Count != 0) { //Create a list of generic Data Entities //***This is a Key piece of the replication process*** //This is where the table list will be stored in a //generic fashion and return in the result. List<DataEntity> dataEntityList = new List<DataEntity>(); //Parse the list of rows that contain the table //information and stuff them into generic data entities. //Add them to the list that will be returned in the result. foreach (DataRow tableRow in tableList.Rows) { var tableName = tableRow["TABLE_NAME"].ToString(); var dataEntity = new DataEntity("Object"); dataEntity.Properties.Add("Name", tableName); dataEntity.Properties.Add( "PrimaryKeyName", PrimaryKeyFieldName); dataEntity.Properties.Add( "Description", GetTableDescription(tableName)); //Check if the table has the ModifiedOn column dataEntity.Properties.Add( "ModificationDateFullName", CheckForLastModifiedColumnName( tableName, metadataAccess) ? LastModifiedFieldName : string.Empty); dataEntity.Properties.Add("Hidden", tableName == Globals.ChangeHistoryTableName); dataEntityList.Add(dataEntity); } //Set the success of the result to true since the //list of entities has been filled. result.Success = true; //Create a new instance of the return result set //with the name of the returned items. result.Return = new DataEntity("ObjectList"); //Add the entity list to the result. result.Return.Properties.Add("Result", dataEntityList); } else { //Set the proper error information in the event that //incorrect schema information is returned from the database. result = SetErrorMethodResult( ErrorCodes.GetObjectList.Number, ErrorCodes.GetObjectList.Description); } } //Return the method result containing the object definition list. return result; }
/// <summary> /// Get a specific Object's definition, this includes any attributes and /// supporting object properties. /// In this case retrieve the table definition along with any columns and /// the definition of each. /// </summary> /// <param name="methodInput">Method Input which includes an 'ObjectName' /// property to determine the object to retrieve the definition.</param> /// <returns>Method Result, which will either include error information or the /// Object Definition of the 'ObjectName' specified in the /// MethodInput properties.</returns> public MethodResult GetObjectDefinition(MethodInput methodInput) { //Create a new instance of the method result to fill with //meta data information MethodResult result = null; //Create a new instance of the metadata access class and pass the //data access instance along with it OleDbMetadataAccess metadataAccess = new OleDbMetadataAccess(_dataAccess); // Use LogMethodExecution to add entry and exit tracing to a method. // When wrapped in a using statement, the exit point // is written during garbage collection. using (new LogMethodExecution( Globals.ConnectorName, "GetObjectDefinition")) { //Get the name of the object in the input properties. string objectName = GetPropertyValueName("ObjectName", methodInput.Input.Properties); //Use the metadata access to get the //definitions for each of the columns in the table. DataTable tableColumnDefinitions = metadataAccess.GetColumnDefinitions(objectName); //Using the meta data access get the definition for the //table indexes (primary and foreign keys) DataTable tableIndexDefinition = metadataAccess.GetTableIndexInformation(objectName); //Check that both sets of data have been returned //from the meta data access layer if ((tableColumnDefinitions != null && tableColumnDefinitions.Rows.Count != 0) && (tableIndexDefinition != null && tableIndexDefinition.Rows.Count != 0)) { //Create a new replication service object RSObjectDefinition rsObjectDefinition = new RSObjectDefinition() { Name = objectName, RSPropertyDefinitions = new List<RSPropertyDefinition>() }; //If this is the change history table set the hidden attribute. //Note: this is how to prevent an object from being replicated. rsObjectDefinition.Hidden = objectName == Globals.ChangeHistoryTableName; List<string> tablePrimaryKeys = GetTablePrimaryKeys(rsObjectDefinition.Name, metadataAccess); //Parse each column returned from the column definitions. //For each column, add a new replication service property definition //to the newly created replication service object definition. foreach (DataRow columnDefinition in tableColumnDefinitions.Rows) { //Process the column definition and set it to the //resplication service property definition. RSPropertyDefinition rsPropertyDefinition = ProcessColumnDefinition(columnDefinition); //Check if this is the default last modified column and //set the object property. if (rsPropertyDefinition.Name == LastModifiedFieldName) { rsObjectDefinition.ModificationDateFullName = rsPropertyDefinition.Name; } //Check if the property is a primary key value. rsPropertyDefinition.InPrimaryKey = tablePrimaryKeys.Contains(rsPropertyDefinition.Name); //Add the property definition to the object definition. rsObjectDefinition.RSPropertyDefinitions.Add(rsPropertyDefinition); } //Convert the replication service object definition to a Data Entity. //Set the result return value to the //replication service object definition. //Set the result Success to true. result = new MethodResult { Success = true, Return = rsObjectDefinition.ToDataEntity() }; } else { //Set the proper error information in the method result in the //event of a null table or column definitions. result = SetErrorMethodResult( ErrorCodes.NoObjectsFound.Number, ErrorCodes.NoObjectsFound.Description); } } //Return the method result. return result; }
public MetadataProvider(OleDbMetadataAccess metadataAccess) { _metadataAccess = metadataAccess; }
/// <summary> /// This method will attempt to connect to the third-party. /// </summary> /// <param name="properties"> /// The collection of information required by this Connector to connect to the third-party. /// </param> public void Connect(IDictionary<string, string> properties) { // Use LogMethodExecution to add entry and exit tracing to a method. // When wrapped in a using statement, the exit point // is written during garbage collection. using (new LogMethodExecution(ConnectorTypeName, "Connect")) { try { //parse the incomming properties to ensure the proper parameters are set BuildConnectionString(properties); //attempt a connection to the selected datasource _dataAccess.OleDbConnect(_connectionString); //open the connection for the metadata access to the server _metaDataAccess = new OleDbMetadataAccess(_dataAccess); //open the connection to the metadata provider _metadataProvider = new MetadataProvider(_metaDataAccess); } catch (OleDbException oleDbException) { string msg = ExceptionFormatter.BuildActionableException( "Unable to Connect to datasource", string.Format("The following error occured in the {0}:", Globals.ConnectorName), oleDbException); //be sure to log any errors that occure while attempting to connect Logger.Write(Logger.Severity.Error, Globals.ConnectorName, msg); //throw the InvalidConnectionException found in the ConnectorApi throw new InvalidConnectionException(msg); } catch (InvalidOperationException invalidOperationException) { string msg = ExceptionFormatter.BuildActionableException( "Unable to connect to datasource the provider information is invalid.", string.Format("The following error occured in the {0}:", Globals.ConnectorName), invalidOperationException); //be sure to log an error that is due to an invalid provider Logger.Write(Logger.Severity.Error, Globals.ConnectorName, msg); //throw the InvalidConnectionException found in the ConnectorApi throw new InvalidConnectionException(msg); } } }