Skip to content

Commit 016939b

Browse files
committed
Migrate away from AutoMapper because it's no longer free.
1 parent 2a117de commit 016939b

File tree

9 files changed

+273
-77
lines changed

9 files changed

+273
-77
lines changed

Directory.Packages.props

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
<GlobalPackageReference Include="Umbraco.GitVersioning.Extensions" Version="0.2.0" />
1212
</ItemGroup>
1313
<ItemGroup>
14-
<PackageVersion Include="AutoMapper" Version="[15.1.0, 15.999.999)" />
15-
<PackageVersion Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="[12.0.1, 12.999.999)" />
1614
<PackageVersion Include="FluentValidation" Version="12.1.0" />
1715
<PackageVersion Include="Microsoft.AspNet.WebApi.Client" Version="[6.0.0, 6.999.999)" />
1816
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />

src/Umbraco.Commerce.ProductFeeds.Infrastructure/DtoMappings/InfrastructureMappingProfile.cs

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using System.Text.Json;
2+
using Umbraco.Commerce.ProductFeeds.Core.Features.FeedSettings.Application;
3+
using Umbraco.Commerce.ProductFeeds.Infrastructure.DbModels;
4+
5+
namespace Umbraco.Commerce.ProductFeeds.Infrastructure.DtoMappings
6+
{
7+
/// <summary>
8+
/// Model mapping for ProductFeedSetting entities.
9+
/// Provides manual mapping between write/read models and database entities.
10+
/// </summary>
11+
public static class ProductFeedSettingMapper
12+
{
13+
/// <summary>
14+
/// Maps from ProductFeedSettingWriteModel to UmbracoCommerceProductFeedSetting (for database storage).
15+
/// This method creates a complete database entity directly from the input data without retrieving existing entities.
16+
/// </summary>
17+
/// <param name="source">The source write model</param>
18+
/// <returns>Mapped database entity ready for insert or update</returns>
19+
public static UmbracoCommerceProductFeedSetting MapToDbModel(ProductFeedSettingWriteModel source)
20+
{
21+
ArgumentNullException.ThrowIfNull(source);
22+
23+
var destination = new UmbracoCommerceProductFeedSetting();
24+
25+
// For edit mode, use the provided ID; for add mode, a new ID will be assigned by the service
26+
destination.Id = source.Id ?? Guid.Empty;
27+
destination.FeedRelativePath = source.FeedRelativePath;
28+
destination.FeedName = source.FeedName;
29+
destination.FeedDescription = source.FeedDescription;
30+
destination.StoreId = source.StoreId;
31+
destination.ProductRootId = source.ProductRootId;
32+
destination.IncludeTaxInPrice = source.IncludeTaxInPrice;
33+
34+
// Parse FeedGeneratorId from string to Guid
35+
if (Guid.TryParse(source.FeedGeneratorId, out Guid feedGeneratorId))
36+
{
37+
destination.FeedGeneratorId = feedGeneratorId;
38+
}
39+
else
40+
{
41+
throw new ArgumentException($"Invalid FeedGeneratorId format: {source.FeedGeneratorId}", nameof(source));
42+
}
43+
44+
// Complex mappings with serialization/joining
45+
destination.ProductPropertyNameMappings = JsonSerializer.Serialize(source.PropertyNameMappings);
46+
destination.ProductChildVariantTypeIds = string.Join(';', source.ProductChildVariantTypeIds.Select(id => id.ToString()));
47+
destination.ProductDocumentTypeIds = string.Join(';', source.ProductDocumentTypeIds.Select(id => id.ToString()));
48+
49+
return destination;
50+
}
51+
52+
/// <summary>
53+
/// Maps from UmbracoCommerceProductFeedSetting to ProductFeedSettingReadModel (for API responses).
54+
/// </summary>
55+
/// <param name="source">The source database entity</param>
56+
/// <returns>Mapped read model</returns>
57+
public static ProductFeedSettingReadModel MapToReadModel(UmbracoCommerceProductFeedSetting source)
58+
{
59+
ArgumentNullException.ThrowIfNull(source);
60+
61+
return new ProductFeedSettingReadModel
62+
{
63+
Id = source.Id,
64+
FeedGeneratorId = source.FeedGeneratorId,
65+
FeedName = source.FeedName,
66+
FeedDescription = source.FeedDescription,
67+
StoreId = source.StoreId,
68+
ProductRootId = source.ProductRootId,
69+
FeedRelativePath = source.FeedRelativePath,
70+
IncludeTaxInPrice = source.IncludeTaxInPrice,
71+
72+
// Complex mappings with deserialization/splitting
73+
PropertyNameMappings = DeserializePropertyMappings(source.ProductPropertyNameMappings),
74+
ProductChildVariantTypeIds = SplitGuidString(source.ProductChildVariantTypeIds),
75+
ProductDocumentTypeIds = SplitGuidString(source.ProductDocumentTypeIds)
76+
};
77+
}
78+
79+
/// <summary>
80+
/// Helper method to deserialize property name mappings from JSON.
81+
/// </summary>
82+
private static ICollection<PropertyAndNodeMapItem> DeserializePropertyMappings(string json)
83+
{
84+
if (string.IsNullOrEmpty(json))
85+
{
86+
return [];
87+
}
88+
89+
try
90+
{
91+
return JsonSerializer.Deserialize<ICollection<PropertyAndNodeMapItem>>(json) ?? [];
92+
}
93+
catch (JsonException)
94+
{
95+
return [];
96+
}
97+
}
98+
99+
/// <summary>
100+
/// Helper method to split semicolon-separated GUID strings into string array.
101+
/// </summary>
102+
private static string[] SplitGuidString(string guidString)
103+
{
104+
if (string.IsNullOrEmpty(guidString))
105+
{
106+
return [];
107+
}
108+
109+
return guidString
110+
.Split(';', StringSplitOptions.RemoveEmptyEntries)
111+
.Where(s => !string.IsNullOrWhiteSpace(s))
112+
.ToArray();
113+
}
114+
}
115+
}

src/Umbraco.Commerce.ProductFeeds.Infrastructure/Implementations/ProductFeedSettingsService.cs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
using System.Text.Json;
2-
using AutoMapper;
32
using Microsoft.Data.SqlClient;
43
using Microsoft.Extensions.Logging;
54
using Umbraco.Cms.Infrastructure.Scoping;
65
using Umbraco.Commerce.ProductFeeds.Core.Features.FeedGenerators.Implementations;
76
using Umbraco.Commerce.ProductFeeds.Core.Features.FeedSettings.Application;
87
using Umbraco.Commerce.ProductFeeds.Infrastructure.DbModels;
8+
using Umbraco.Commerce.ProductFeeds.Infrastructure.DtoMappings;
99

1010
namespace Umbraco.Commerce.ProductFeeds.Infrastructure.Implementations
1111
{
1212
internal class ProductFeedSettingsService : IProductFeedSettingsService
1313
{
1414
private readonly IScopeProvider _scopeProvider;
15-
private readonly IMapper _mapper;
1615
private readonly ILogger<ProductFeedSettingsService> _logger;
1716
private readonly FeedGeneratorCollection _feedGenerators;
1817

1918
public ProductFeedSettingsService(
2019
IScopeProvider scopeProvider,
21-
IMapper mapper,
2220
ILogger<ProductFeedSettingsService> logger,
2321
FeedGeneratorCollection feedGenerators)
2422
{
2523
_scopeProvider = scopeProvider;
26-
_mapper = mapper;
2724
_logger = logger;
2825
_feedGenerators = feedGenerators;
2926
}
@@ -56,7 +53,7 @@ from umbracoCommerceProductFeedSetting
5653
throw new InvalidOperationException($"Unknown feed generator detected. Id: '{feedSetting.FeedGeneratorId}'.");
5754
}
5855

59-
ProductFeedSettingReadModel readModel = _mapper.Map<ProductFeedSettingReadModel>(feedSetting);
56+
ProductFeedSettingReadModel readModel = ProductFeedSettingMapper.MapToReadModel(feedSetting);
6057
return readModel;
6158
}
6259

@@ -78,39 +75,48 @@ from umbracoCommerceProductFeedSetting
7875
return [];
7976
}
8077

81-
return _mapper.Map<List<ProductFeedSettingReadModel>>(settings);
78+
return settings.Select(setting => ProductFeedSettingMapper.MapToReadModel(setting)).ToList();
8279
}
8380

8481
/// <inheritdoc/>
8582
public async Task<Guid?> SaveSettingAsync(ProductFeedSettingWriteModel input)
8683
{
87-
UmbracoCommerceProductFeedSetting dbModel = _mapper.Map<UmbracoCommerceProductFeedSetting>(input);
88-
8984
try
9085
{
9186
using IScope scope = _scopeProvider.CreateScope();
87+
88+
// Create the database model directly from input data
89+
UmbracoCommerceProductFeedSetting dbModel = ProductFeedSettingMapper.MapToDbModel(input);
90+
9291
if (input.Id == null)
9392
{
94-
// add mode
93+
// Add mode - generate new ID and insert
9594
dbModel.Id = Guid.NewGuid();
9695
_ = await scope.Database.InsertAsync(dbModel).ConfigureAwait(false);
96+
scope.Complete();
97+
return dbModel.Id;
9798
}
9899
else
99100
{
100-
// edit mode
101+
// Edit mode - update directly without retrieving existing entity
101102
int affectedRowCount = await scope.Database.UpdateAsync(dbModel).ConfigureAwait(false);
102103
if (affectedRowCount != 1)
103104
{
105+
scope.Complete();
104106
return null;
105107
}
106-
}
107108

108-
scope.Complete();
109-
return dbModel.Id;
109+
scope.Complete();
110+
return dbModel.Id;
111+
}
110112
}
111113
catch (SqlException ex)
112114
{
113-
_logger.LogError(ex, "Unable to add a new record. Data: {Data}", JsonSerializer.Serialize(input));
115+
if (_logger.IsEnabled(LogLevel.Error))
116+
{
117+
_logger.LogError(ex, "Unable to save record. Data: {Data}", JsonSerializer.Serialize(input));
118+
}
119+
114120
return null;
115121
}
116122
}
@@ -131,7 +137,11 @@ public async Task<bool> DeleteSettingAsync(Guid id)
131137
}
132138
catch (SqlException ex)
133139
{
134-
_logger.LogError(ex, "Unable to delete the record with id = {Id}", id);
140+
if (_logger.IsEnabled(LogLevel.Error))
141+
{
142+
_logger.LogError(ex, "Unable to delete the record with id = {Id}", id);
143+
}
144+
135145
return false;
136146
}
137147
}

src/Umbraco.Commerce.ProductFeeds.Infrastructure/Umbraco.Commerce.ProductFeeds.Infrastructure.csproj

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@
88
<NoWarn>IDE0007;CA1848;IDE0058;CA2007;IDE0022;IDE0021;IDE0290;</NoWarn>
99
</PropertyGroup>
1010

11-
<ItemGroup>
12-
<PackageReference Include="AutoMapper" />
13-
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" />
14-
</ItemGroup>
15-
1611
<ItemGroup>
1712
<ProjectReference Include="..\Umbraco.Commerce.ProductFeeds.Core\Umbraco.Commerce.ProductFeeds.Core.csproj" />
1813
</ItemGroup>

src/Umbraco.Commerce.ProductFeeds.Startup/Initializations/IUmbracoCommerceBuilderExtensions.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using Umbraco.Commerce.ProductFeeds.Core.Features.ProductQueries.Application;
1212
using Umbraco.Commerce.ProductFeeds.Core.Features.ProductQueries.Implementations;
1313
using Umbraco.Commerce.ProductFeeds.Core.Features.PropertyValueExtractors.Implementations;
14-
using Umbraco.Commerce.ProductFeeds.Infrastructure.DtoMappings;
1514
using Umbraco.Commerce.ProductFeeds.Infrastructure.Implementations;
1615
using Umbraco.Commerce.ProductFeeds.Infrastructure.Migrations;
1716
using Umbraco.Commerce.ProductFeeds.Startup.Initializations;
@@ -34,7 +33,6 @@ public static IUmbracoCommerceBuilder AddCommerceProductFeeds(this IUmbracoComme
3433
ucBuilder.AddSwagger();
3534
ucBuilder.AddServices();
3635
ucBuilder.AddDbMigrations();
37-
ucBuilder.AddAutoMapper();
3836
return ucBuilder;
3937
}
4038

@@ -50,12 +48,6 @@ private static IUmbracoCommerceBuilder AddDbMigrations(this IUmbracoCommerceBuil
5048
return builder;
5149
}
5250

53-
private static IUmbracoCommerceBuilder AddAutoMapper(this IUmbracoCommerceBuilder builder)
54-
{
55-
builder.Services.AddAutoMapper(typeof(InfrastructureMappingProfile));
56-
return builder;
57-
}
58-
5951
private static void AddServices(this IUmbracoCommerceBuilder builder)
6052
{
6153
IServiceCollection services = builder.Services;

tests/Umbraco.Commerce.ProductFeeds.Infrastructure.UnitTests/AutoMapperTests.cs

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)