Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>10.9.1</Version>
<Version>10.9.2</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<Title>Dynamicweb Provider</Title>
<Description>Dynamicweb Provider</Description>
Expand Down
208 changes: 118 additions & 90 deletions src/DynamicwebProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
public DynamicwebProvider(string connectionString)
{
SqlConnectionString = connectionString;
connection = new SqlConnection(SqlConnectionString);
_connection = new SqlConnection(SqlConnectionString);
}

#region HideParameters
Expand Down Expand Up @@ -137,11 +137,11 @@
}
#endregion

protected SqlConnection connection;
protected SqlConnection _connection;
protected SqlConnection Connection
{
get { return connection ??= (SqlConnection)Database.CreateConnection(); }
set { connection = value; }
get { return _connection ??= (SqlConnection)Database.CreateConnection(); }
set { _connection = value; }
}

protected string defaultLanguage = null;
Expand Down Expand Up @@ -227,7 +227,7 @@
xmlTextWriter.WriteElementString("Shop", Shop);
xmlTextWriter.WriteElementString("DeleteProductsAndGroupForSpecificLanguage", DeleteProductsAndGroupForSpecificLanguage.ToString(CultureInfo.CurrentCulture));
xmlTextWriter.WriteElementString("DefaultLanguage", DefaultLanguage);
xmlTextWriter.WriteElementString("RepositoriesIndexUpdate", RepositoriesIndexUpdate);

Check warning on line 230 in src/DynamicwebProvider.cs

View workflow job for this annotation

GitHub Actions / call-workflow / Build

'DynamicwebProvider.RepositoriesIndexUpdate' is obsolete: 'Use Job.RepositoriesIndexSettings'
xmlTextWriter.WriteElementString("DiscardDuplicates", DiscardDuplicates.ToString(CultureInfo.CurrentCulture));
xmlTextWriter.WriteElementString("HideDeactivatedProducts", HideDeactivatedProducts.ToString(CultureInfo.CurrentCulture));
xmlTextWriter.WriteElementString("SkipFailingRows", SkipFailingRows.ToString(CultureInfo.CurrentCulture));
Expand Down Expand Up @@ -330,7 +330,7 @@
case "RepositoriesIndexUpdate":
if (node.HasChildNodes)
{
RepositoriesIndexUpdate = node.FirstChild.Value;

Check warning on line 333 in src/DynamicwebProvider.cs

View workflow job for this annotation

GitHub Actions / call-workflow / Build

'DynamicwebProvider.RepositoriesIndexUpdate' is obsolete: 'Use Job.RepositoriesIndexSettings'
}
break;
case "DiscardDuplicates":
Expand Down Expand Up @@ -460,19 +460,21 @@

public override bool RunJob(Job job)
{
if (Connection.State != ConnectionState.Open)
Connection.Open();

if (IsFirstJobRun)
{
OrderTablesByConstraints(job, Connection);
}
SqlTransaction sqlTransaction = null;
Dictionary<string, object> sourceRow = null;
bool isReadFromSourceFinished = IsReadingSourceXmlFinished(job);
Exception exception = null;
bool deactivateMissingProducts = false;
try
{
ReplaceMappingConditionalsWithValuesFromRequest(job);
if (Connection.State != ConnectionState.Open)
Connection.Open();

foreach (Mapping mapping in job.Mappings)
{
Expand All @@ -499,9 +501,9 @@
{
Column randomColumn = mapping.SourceTable.Columns.First();
var languageColumnMapping = mapping.AddMapping(randomColumn, mapping.DestinationTable.Columns.Find(c => string.Compare(c.Name, MappingExtensions.GetLanguageIdColumnName(mapping.DestinationTable.Name), true) == 0));
languageColumnMapping.ScriptTypeProvider = new ConstantScriptType()
{
ScriptValue = defaultLanguage
languageColumnMapping.ScriptTypeProvider = new ConstantScriptType()
{
ScriptValue = defaultLanguage
};
}
}
Expand Down Expand Up @@ -548,115 +550,118 @@
}

sourceRow = null;
sqlTransaction = Connection.BeginTransaction();

deactivateMissingProducts = DeactivateMissingProducts;
var productsWriter = Writers.Where(w => w.Mapping != null && w.Mapping.Active && w.Mapping.DestinationTable != null &&
w.Mapping.DestinationTable.Name == "EcomProducts").FirstOrDefault();
if (productsWriter != null)
if (isReadFromSourceFinished)
{
bool? value = productsWriter.Mapping.GetOptionValue("DeactivateMissingProducts");
deactivateMissingProducts = value.HasValue ? value.Value : DeactivateMissingProducts;
}
sqlTransaction = Connection.BeginTransaction();

if (deactivateMissingProducts)
HandleProductsWriter(Writers);
deactivateMissingProducts = DeactivateMissingProducts;
var productsWriter = Writers.Where(w => w.Mapping != null && w.Mapping.Active && w.Mapping.DestinationTable != null &&
w.Mapping.DestinationTable.Name == "EcomProducts").FirstOrDefault();
if (productsWriter != null)
{
bool? value = productsWriter.Mapping.GetOptionValue("DeactivateMissingProducts");
deactivateMissingProducts = value.HasValue ? value.Value : DeactivateMissingProducts;
}

foreach (DynamicwebBulkInsertDestinationWriter writer in Writers)
{
bool? optionValue = writer.Mapping.GetOptionValue("DeleteIncomingItems");
bool deleteIncomingItems = optionValue.HasValue ? optionValue.Value : DeleteIncomingItems;
if (deactivateMissingProducts)
HandleProductsWriter(Writers);

if (writer.RowsToWriteCount > 0)
foreach (DynamicwebBulkInsertDestinationWriter writer in Writers)
{
if (deleteIncomingItems)
bool? optionValue = writer.Mapping.GetOptionValue("DeleteIncomingItems");
bool deleteIncomingItems = optionValue.HasValue ? optionValue.Value : DeleteIncomingItems;

if (writer.RowsToWriteCount > 0)
{
int rowsAffected = writer.DeleteExistingFromMainTable(Shop, sqlTransaction);
if (rowsAffected > 0)
if (deleteIncomingItems)
{
Logger.Log($"The number of deleted rows: {rowsAffected} for the destination {writer.Mapping.DestinationTable.Name} table mapping");
TotalRowsAffected += rowsAffected;
int rowsAffected = writer.DeleteExistingFromMainTable(Shop, sqlTransaction);
if (rowsAffected > 0)
{
Logger.Log($"The number of deleted rows: {rowsAffected} for the destination {writer.Mapping.DestinationTable.Name} table mapping");
TotalRowsAffected += rowsAffected;
}
}
}
else
{
writer.AddMappingsToJobThatNeedsToBeThereForMoveToMainTables(job);
DynamicwebBulkInsertDestinationWriter.RemoveColumnMappingsFromJobThatShouldBeSkippedInMoveToMainTables(job);
else
{
writer.AddMappingsToJobThatNeedsToBeThereForMoveToMainTables(job);
DynamicwebBulkInsertDestinationWriter.RemoveColumnMappingsFromJobThatShouldBeSkippedInMoveToMainTables(job);

optionValue = writer.Mapping.GetOptionValue("UpdateOnlyExistingRecords");
bool updateOnlyExistingRecords = optionValue.HasValue ? optionValue.Value : UpdateOnlyExistingRecords;
optionValue = writer.Mapping.GetOptionValue("UpdateOnlyExistingRecords");
bool updateOnlyExistingRecords = optionValue.HasValue ? optionValue.Value : UpdateOnlyExistingRecords;

int rowsAffected = writer.MoveDataToMainTable(sqlTransaction, updateOnlyExistingRecords, InsertOnlyNewRecords);
if (rowsAffected > 0)
{
Logger.Log($"The number of rows affected: {rowsAffected} in the {writer.Mapping.DestinationTable.Name} table");
TotalRowsAffected += rowsAffected;
int rowsAffected = writer.MoveDataToMainTable(sqlTransaction, updateOnlyExistingRecords, InsertOnlyNewRecords);
if (rowsAffected > 0)
{
Logger.Log($"The number of rows affected: {rowsAffected} in the {writer.Mapping.DestinationTable.Name} table");
TotalRowsAffected += rowsAffected;
}
}
}
}
else
{
if (!deleteIncomingItems)
else
{
Logger.Log(string.Format("No rows were imported to the table: {0}.", writer.Mapping.DestinationTable.Name));
if (!deleteIncomingItems)
{
Logger.Log(string.Format("No rows were imported to the table: {0}.", writer.Mapping.DestinationTable.Name));
}
}
}
}

if (RemoveMissingRows)
{
var distinctWriters = Enumerable.Reverse(Writers).DistinctBy(obj => obj.Mapping.DestinationTable);
if (distinctWriters != null)
if (RemoveMissingRows)
{
foreach (var distinctWriter in distinctWriters)
var distinctWriters = Enumerable.Reverse(Writers).DistinctBy(obj => obj.Mapping.DestinationTable);
if (distinctWriters != null)
{
if (distinctWriter == null || distinctWriter.Mapping == null)
continue;
foreach (var distinctWriter in distinctWriters)
{
if (distinctWriter == null || distinctWriter.Mapping == null)
continue;

var sameWriters = Writers.Where(obj => obj.Mapping != null && obj.Mapping.DestinationTable != null && obj.Mapping.DestinationTable.Name.Equals(distinctWriter.Mapping.DestinationTable?.Name ?? "", StringComparison.OrdinalIgnoreCase)).ToList();
if (sameWriters.Count == 0)
continue;
var sameWriters = Writers.Where(obj => obj.Mapping != null && obj.Mapping.DestinationTable != null && obj.Mapping.DestinationTable.Name.Equals(distinctWriter.Mapping.DestinationTable?.Name ?? "", StringComparison.OrdinalIgnoreCase)).ToList();
if (sameWriters.Count == 0)
continue;

Dictionary<string, Mapping> mappings = sameWriters.ToDictionary(obj => $"{obj.GetTempTableName}", obj => obj.Mapping);
if (mappings == null || mappings.Count == 0)
continue;
Dictionary<string, Mapping> mappings = sameWriters.ToDictionary(obj => $"{obj.GetTempTableName}", obj => obj.Mapping);
if (mappings == null || mappings.Count == 0)
continue;

TotalRowsAffected += sameWriters[0].DeleteExcessFromMainTable(Shop, sqlTransaction, mappings);
TotalRowsAffected += sameWriters[0].DeleteExcessFromMainTable(Shop, sqlTransaction, mappings);
}
}
}
}
else
{
foreach (DynamicwebBulkInsertDestinationWriter writer in Enumerable.Reverse(Writers))
else
{
bool? optionValue = writer.Mapping.GetOptionValue("DeleteIncomingItems");
bool deleteIncomingItems = optionValue.HasValue ? optionValue.Value : DeleteIncomingItems;

if (!deleteIncomingItems && writer.RowsToWriteCount > 0)
foreach (DynamicwebBulkInsertDestinationWriter writer in Enumerable.Reverse(Writers))
{
TotalRowsAffected += writer.DeleteExcessFromMainTable(Shop, sqlTransaction, DeleteProductsAndGroupForSpecificLanguage, defaultLanguage, HideDeactivatedProducts);
bool? optionValue = writer.Mapping.GetOptionValue("DeleteIncomingItems");
bool deleteIncomingItems = optionValue.HasValue ? optionValue.Value : DeleteIncomingItems;

if (!deleteIncomingItems && writer.RowsToWriteCount > 0)
{
TotalRowsAffected += writer.DeleteExcessFromMainTable(Shop, sqlTransaction, DeleteProductsAndGroupForSpecificLanguage, defaultLanguage, HideDeactivatedProducts);
}
}
}
}

if (PartialUpdate)
{
//if PartilUpdate property is set, we still want to remove rows from the EcomGroupProductRelationsTable, but only for the products that are being imported
DynamicwebBulkInsertDestinationWriter groupProductRelationWriter = Writers.Find(w => w.Mapping.DestinationTable != null && w.Mapping.DestinationTable.Name == "EcomGroupProductRelation");
if (groupProductRelationWriter != null && groupProductRelationWriter.RowsToWriteCount > 0)
if (PartialUpdate)
{
bool? optionValue = groupProductRelationWriter.Mapping.GetOptionValue("DeleteIncomingItems");
bool deleteIncomingItems = optionValue.HasValue ? optionValue.Value : DeleteIncomingItems;
if (!deleteIncomingItems)
//if PartilUpdate property is set, we still want to remove rows from the EcomGroupProductRelationsTable, but only for the products that are being imported
DynamicwebBulkInsertDestinationWriter groupProductRelationWriter = Writers.Find(w => w.Mapping.DestinationTable != null && w.Mapping.DestinationTable.Name == "EcomGroupProductRelation");
if (groupProductRelationWriter != null && groupProductRelationWriter.RowsToWriteCount > 0)
{
TotalRowsAffected += groupProductRelationWriter.DeleteExcessGroupProductsRelationsTable();
bool? optionValue = groupProductRelationWriter.Mapping.GetOptionValue("DeleteIncomingItems");
bool deleteIncomingItems = optionValue.HasValue ? optionValue.Value : DeleteIncomingItems;
if (!deleteIncomingItems)
{
TotalRowsAffected += groupProductRelationWriter.DeleteExcessGroupProductsRelationsTable();
}
}
}
}

sqlTransaction.Commit();
AssortmentHandler?.RebuildAssortments();
MoveRepositoriesIndexToJob(job);
sqlTransaction.Commit();
AssortmentHandler?.RebuildAssortments();
MoveRepositoriesIndexToJob(job);
}
}
catch (Exception ex)
{
Expand Down Expand Up @@ -692,12 +697,16 @@
}
finally
{
foreach (var writer in Writers)
if (exception != null || isReadFromSourceFinished)
{
writer.Close();
foreach (var writer in Writers)
{
writer.Close();
}
job.Source.Close();
_connection.Dispose();
_connection = null;
}
job.Source.Close();
Connection.Dispose();
sourceRow = null;
}
if (IsFirstJobRun)
Expand All @@ -709,15 +718,15 @@

private void MoveRepositoriesIndexToJob(Job job)
{
if (!string.IsNullOrEmpty(RepositoriesIndexUpdate))

Check warning on line 721 in src/DynamicwebProvider.cs

View workflow job for this annotation

GitHub Actions / call-workflow / Build

'DynamicwebProvider.RepositoriesIndexUpdate' is obsolete: 'Use Job.RepositoriesIndexSettings'
{
char[] separator = [','];
// if the provider already have RepositoriesIndexUpdate set, then we move them to the job, and set the add-in to string.empty
if (job.RepositoriesIndexSettings?.RepositoriesIndexes?.Count == 0)
{
job.RepositoriesIndexSettings = new RepositoriesIndexSettings(new Collection<string>([.. RepositoriesIndexUpdate.Split(separator, StringSplitOptions.RemoveEmptyEntries)]));

Check warning on line 727 in src/DynamicwebProvider.cs

View workflow job for this annotation

GitHub Actions / call-workflow / Build

'DynamicwebProvider.RepositoriesIndexUpdate' is obsolete: 'Use Job.RepositoriesIndexSettings'
}
RepositoriesIndexUpdate = string.Empty;

Check warning on line 729 in src/DynamicwebProvider.cs

View workflow job for this annotation

GitHub Actions / call-workflow / Build

'DynamicwebProvider.RepositoriesIndexUpdate' is obsolete: 'Use Job.RepositoriesIndexSettings'
job.Save();
}
}
Expand Down Expand Up @@ -883,7 +892,7 @@

public override void Close()
{
Connection.Close();
_connection?.Close();
}

public override ISourceReader GetReader(Mapping mapping)
Expand All @@ -907,4 +916,23 @@
}
return result;
}

private bool IsReadingSourceXmlFinished(Job job)
{
if (job.Source != null)
{
bool isXmlProviderUsed = job.Source.GetType().Name.EndsWith("XmlProvider", StringComparison.OrdinalIgnoreCase);
if (isXmlProviderUsed)
{
var exportIsDoneProperty = job.Source.GetType().GetField("ExportIsDone");
var exportIsDoneValue = exportIsDoneProperty?.GetValue(job.Source);
if (exportIsDoneValue is not null)
{
return Converter.ToBoolean(exportIsDoneValue);
}
}
}
return true;
}

}
Loading