diff --git a/BenchmarkSuite1/BenchmarkSuite1.csproj b/BenchmarkSuite1/BenchmarkSuite1.csproj
new file mode 100644
index 0000000..44499fa
--- /dev/null
+++ b/BenchmarkSuite1/BenchmarkSuite1.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net8.0
+ Exe
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BenchmarkSuite1/ProductsWriteStoreBenchmarks.cs b/BenchmarkSuite1/ProductsWriteStoreBenchmarks.cs
new file mode 100644
index 0000000..eb42da6
--- /dev/null
+++ b/BenchmarkSuite1/ProductsWriteStoreBenchmarks.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Threading.Tasks;
+using BenchmarkDotNet.Attributes;
+using Distribt.Services.Products.BusinessLogic.DataAccess;
+using Distribt.Services.Products.Dtos;
+using Microsoft.EntityFrameworkCore;
+
+namespace Benchmarks.Products
+{
+ [MemoryDiagnoser]
+ public class ProductsWriteStoreBenchmarks
+ {
+ private static DbContextOptions NewOptions()
+ => new DbContextOptionsBuilder()
+ .UseInMemoryDatabase(Guid.NewGuid().ToString())
+ .Options;
+
+ [Benchmark]
+ public async Task CreateRecord_Isolated()
+ {
+ var options = NewOptions();
+ await using var store = new ProductsWriteStore(options);
+
+ var details = new ProductDetails(
+ Name: "Product-" + Guid.NewGuid().ToString("N"),
+ Description: "Desc-" + Guid.NewGuid().ToString("N")
+ );
+
+ _ = await store.CreateRecord(details);
+ }
+
+ [Benchmark]
+ public async Task UpdateProduct_Isolated()
+ {
+ var options = NewOptions();
+ await using var store = new ProductsWriteStore(options);
+
+ // Seed a product to update in this isolated database
+ var existingId = await store.CreateRecord(new ProductDetails(
+ Name: "Seed-" + Guid.NewGuid().ToString("N"),
+ Description: "Seed-Desc"
+ ));
+
+ var updateDetails = new ProductDetails(
+ Name: "Updated-" + Guid.NewGuid().ToString("N"),
+ Description: "Updated-Desc"
+ );
+
+ await store.UpdateProduct(existingId, updateDetails);
+ }
+ }
+}
\ No newline at end of file
diff --git a/BenchmarkSuite1/Program.cs b/BenchmarkSuite1/Program.cs
new file mode 100644
index 0000000..68e2fdd
--- /dev/null
+++ b/BenchmarkSuite1/Program.cs
@@ -0,0 +1,12 @@
+using BenchmarkDotNet.Running;
+
+namespace BenchmarkSuite1
+{
+ internal class Program
+ {
+ static void Main(string[] args)
+ {
+ var _ = BenchmarkRunner.Run(typeof(Program).Assembly);
+ }
+ }
+}
diff --git a/Distribt.sln b/Distribt.sln
index 7274e8a..dc7a3fa 100644
--- a/Distribt.sln
+++ b/Distribt.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31815.197
+# Visual Studio Version 18
+VisualStudioVersion = 18.0.10928.107 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Api", "Api", "{25E556CF-D2DB-4BA2-9379-07CD4976BA9E}"
EndProject
@@ -93,6 +93,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Discovery", "Discovery", "{
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Distribt.Test.Shared.Discovery.Tests", "src\Tests\Shared\Discovery\Distribt.Test.Shared.Discovery.Tests\Distribt.Test.Shared.Discovery.Tests.csproj", "{F9C0F635-D488-4E1F-A4AA-912EA8C518B5}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkSuite1", "BenchmarkSuite1\BenchmarkSuite1.csproj", "{A20861A9-411E-6150-BF5C-69E8196E5D22}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -211,6 +213,10 @@ Global
{F9C0F635-D488-4E1F-A4AA-912EA8C518B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9C0F635-D488-4E1F-A4AA-912EA8C518B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9C0F635-D488-4E1F-A4AA-912EA8C518B5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A20861A9-411E-6150-BF5C-69E8196E5D22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A20861A9-411E-6150-BF5C-69E8196E5D22}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A20861A9-411E-6150-BF5C-69E8196E5D22}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A20861A9-411E-6150-BF5C-69E8196E5D22}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Services/Products/Distribt.Services.Products.Api.Write/Properties/launchSettings.json b/src/Services/Products/Distribt.Services.Products.Api.Write/Properties/launchSettings.json
index b06f58a..5aef3be 100644
--- a/src/Services/Products/Distribt.Services.Products.Api.Write/Properties/launchSettings.json
+++ b/src/Services/Products/Distribt.Services.Products.Api.Write/Properties/launchSettings.json
@@ -14,7 +14,7 @@
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
- "applicationUrl": "https://localhost:60320;http://localhost:60310",
+ "applicationUrl": "https://localhost:60321;http://localhost:60311",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"VAULT-TOKEN": "vault-distribt-token"
diff --git a/src/Services/Products/Distribt.Services.Products.BusinessLogic/DataAccess/ProductsWriteStore.cs b/src/Services/Products/Distribt.Services.Products.BusinessLogic/DataAccess/ProductsWriteStore.cs
index 313cc07..01c5868 100644
--- a/src/Services/Products/Distribt.Services.Products.BusinessLogic/DataAccess/ProductsWriteStore.cs
+++ b/src/Services/Products/Distribt.Services.Products.BusinessLogic/DataAccess/ProductsWriteStore.cs
@@ -17,12 +17,33 @@ public class ProductsWriteStore : DbContext, IProductsWriteStore
public ProductsWriteStore(DbContextOptions options) : base(options)
{
}
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.Entity(b =>
+ {
+ b.HasKey(p => p.Id);
+ b.Property(p => p.Id).ValueGeneratedOnAdd();
+ b.Property(p => p.Name).IsRequired(false);
+ b.Property(p => p.Description).IsRequired(false);
+ b.ToTable("Products");
+ });
+ }
+
public async Task UpdateProduct(int id, ProductDetails details)
{
- var product = await Products.SingleAsync(a => a.Id == id);
- product.Description = details.Description;
+ // Avoid extra round-trip: attach a stub entity and mark only changed properties as modified
+ var product = new ProductDetailEntity { Id = id };
+ Attach(product);
+
product.Name = details.Name;
-
+ product.Description = details.Description;
+
+ Entry(product).Property(p => p.Name).IsModified = true;
+ Entry(product).Property(p => p.Description).IsModified = true;
+
await SaveChangesAsync();
}
@@ -34,16 +55,16 @@ public async Task CreateRecord(ProductDetails details)
Name = details.Name
};
- var result = await Products.AddAsync(newProduct);
+ Products.Add(newProduct);
await SaveChangesAsync();
- return result.Entity.Id ?? throw new ApplicationException("the record has not been inserted in the db");
+ return newProduct.Id;
}
private class ProductDetailEntity
{
- public int? Id { get; set; }
+ public int Id { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
}