Skip to content

Commit

Permalink
refactor: Replace Azure SQL Edge with PostgreSQL (#1156)
Browse files Browse the repository at this point in the history
  • Loading branch information
HofmeisterAn authored Apr 15, 2024
1 parent aaafffc commit 136ca49
Show file tree
Hide file tree
Showing 15 changed files with 42 additions and 41 deletions.
4 changes: 2 additions & 2 deletions examples/WeatherForecast/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.1"/>
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.1"/>
<PackageVersion Include="Microsoft.Fast.Components.FluentUI" Version="3.5.4"/>
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2"/>
<!-- Unit and integration test dependencies: -->
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.1"/>
<PackageVersion Include="Testcontainers.SqlEdge" Version="3.7.0"/>
<PackageVersion Include="Testcontainers.PostgreSql" Version="3.8.0"/>
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.7"/>
<PackageVersion Include="xunit" Version="2.7.0"/>
<!-- Third-party client dependencies to connect and interact with the containers: -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Map all read-only properties. There is not [Mapped] attribute like [NotMapped].
modelBuilder.Entity<WeatherData>().Property(weatherData => weatherData.Id);
modelBuilder.Entity<WeatherData>().Property(weatherData => weatherData.Date);
modelBuilder.Entity<WeatherData>().Property(weatherData => weatherData.Period);
modelBuilder.Entity<Temperature>().Property(temperature => temperature.Id);
modelBuilder.Entity<Temperature>().Property(temperature => temperature.UnitName);
modelBuilder.Entity<Temperature>().Property(temperature => temperature.UnitSymbol);
modelBuilder.Entity<Temperature>().Property(temperature => temperature.Value);
modelBuilder.Entity<Temperature>().Property(temperature => temperature.Measured);
modelBuilder.Entity<WeatherData>().HasMany(weatherData => weatherData.Temperatures).WithOne().HasForeignKey(temperature => temperature.BelongsTo);

var weatherDataSeed = Enumerable.Range(0, 30).Select(_ => Guid.NewGuid()).Select((id, day) => new WeatherData(id, DateTime.Today.AddDays(day))).ToList();
var temperatureSeed = weatherDataSeed.SelectMany(data => Enumerable.Range(0, 23).Select(hour => Temperature.Celsius(data.Id, Random.Shared.Next(-10, 30), data.Date.AddHours(hour)))).ToList();
var weatherDataSeed = Enumerable.Range(0, 30).Select(_ => Guid.NewGuid()).Select((id, day) => new WeatherData(id, DateTimeOffset.Now.AddDays(day))).ToList();
var temperatureSeed = weatherDataSeed.SelectMany(data => Enumerable.Range(0, 23).Select(hour => Temperature.Celsius(data.Id, Random.Shared.Next(-10, 30), data.Period.AddHours(hour)))).ToList();

modelBuilder.Entity<Temperature>().HasData(temperatureSeed);
modelBuilder.Entity<WeatherData>().HasData(weatherDataSeed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public Task<IEnumerable<WeatherData>> GetAllAsync()

public Task<IEnumerable<WeatherData>> GetAllAsync(string latitude, string longitude, DateTime from, DateTime to)
{
return Task.FromResult<IEnumerable<WeatherData>>(_context.WeatherData.Include(property => property.Temperatures).OrderBy(weatherData => weatherData.Date).Take(to.Subtract(from).Days));
return Task.FromResult<IEnumerable<WeatherData>>(_context.WeatherData.Include(property => property.Temperatures).OrderBy(weatherData => weatherData.Period).Take(to.Subtract(from).Days));
}

public Task<WeatherData> GetAsync(Guid id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace WeatherForecast.Entities;
public sealed class Temperature : HasId
{
[JsonConstructor]
public Temperature(Guid id, Guid belongsTo, string unitName, string unitSymbol, double value, DateTime measured) : base(id)
public Temperature(Guid id, Guid belongsTo, string unitName, string unitSymbol, double value, DateTimeOffset measured) : base(id)
{
BelongsTo = belongsTo;
UnitName = unitName;
Expand All @@ -13,7 +13,7 @@ public Temperature(Guid id, Guid belongsTo, string unitName, string unitSymbol,
Measured = measured;
}

public static Temperature AbsoluteZero { get; } = Kelvin(Guid.Empty, 0, DateTime.MinValue);
public static Temperature AbsoluteZero { get; } = Kelvin(Guid.Empty, 0, DateTimeOffset.MinValue);

[JsonPropertyName("belongsTo")]
public Guid BelongsTo { get; }
Expand All @@ -28,19 +28,19 @@ public Temperature(Guid id, Guid belongsTo, string unitName, string unitSymbol,
public double Value { get; }

[JsonPropertyName("measured")]
public DateTime Measured { get; }
public DateTimeOffset Measured { get; }

public static Temperature Kelvin(Guid belongsTo, double value, DateTime measured)
public static Temperature Kelvin(Guid belongsTo, double value, DateTimeOffset measured)
{
return new Temperature(Guid.NewGuid(), belongsTo, "Kelvin", "K", value, measured);
}

public static Temperature Celsius(Guid belongsTo, double value, DateTime measured)
public static Temperature Celsius(Guid belongsTo, double value, DateTimeOffset measured)
{
return new Temperature(Guid.NewGuid(), belongsTo, "degree Celsius", "°C", value, measured);
}

public static Temperature Fahrenheit(Guid belongsTo, double value, DateTime measured)
public static Temperature Fahrenheit(Guid belongsTo, double value, DateTimeOffset measured)
{
return new Temperature(Guid.NewGuid(), belongsTo, "degree Fahrenheit", "°F", value, measured);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@ namespace WeatherForecast.Entities;
[PublicAPI]
public sealed class WeatherData : HasId
{
public WeatherData(Guid id, DateTime date) : this(id, date, new List<Temperature>())
public WeatherData(Guid id, DateTimeOffset period) : this(id, period, new List<Temperature>())
{
// Entity Framework constructor.
}

[JsonConstructor]
public WeatherData(Guid id, DateTime date, IList<Temperature> temperatures) : base(id)
public WeatherData(Guid id, DateTimeOffset period, IList<Temperature> temperatures) : base(id)
{
Date = date;
Period = period;
Minimum = temperatures.OrderBy(temperature => temperature.Value).DefaultIfEmpty(Temperature.AbsoluteZero).First();
Maximum = temperatures.OrderBy(temperature => temperature.Value).DefaultIfEmpty(Temperature.AbsoluteZero).Last();
Temperatures = temperatures;
}

[JsonPropertyName("date")]
public DateTime Date { get; }
[JsonPropertyName("period")]
public DateTimeOffset Period { get; }

[JsonIgnore]
public Temperature Minimum { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public sealed class WeatherForecastController : ControllerBase, IDisposable
{
private readonly ISearchCityOrZipCode _searchCityOrZipCode;

private readonly EventWaitHandle _wait = new AutoResetEvent(false);
private readonly SemaphoreSlim _wait = new SemaphoreSlim(0, 1);

private IEnumerable<WeatherData> _weatherData = Array.Empty<WeatherData>();

Expand All @@ -29,7 +29,8 @@ public async Task<ActionResult<IEnumerable<WeatherData>>> GetWeatherForecast()
await _searchCityOrZipCode.ExecuteAsync(string.Empty)
.ConfigureAwait(false);

_wait.WaitOne();
await _wait.WaitAsync()
.ConfigureAwait(false);

return Ok(_weatherData);
}
Expand All @@ -41,6 +42,6 @@ private void SearchCityOrZipCodeResultPublished(object? sender, ResultInfo<IEnum
_weatherData = result.Value;
}

_wait.Set();
_wait.Release();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ namespace WeatherForecast;

public sealed class DatabaseContainer : IHostedService
{
private readonly SqlEdgeContainer _sqlEdgeContainer = new SqlEdgeBuilder().Build();
private readonly PostgreSqlContainer _postgreSqlContainer = new PostgreSqlBuilder().Build();

public Task StartAsync(CancellationToken cancellationToken)
{
return _sqlEdgeContainer.StartAsync(cancellationToken);
return _postgreSqlContainer.StartAsync(cancellationToken);
}

public Task StopAsync(CancellationToken cancellationToken)
{
return _sqlEdgeContainer.StopAsync(cancellationToken);
return _postgreSqlContainer.StopAsync(cancellationToken);
}

public string GetConnectionString()
{
return _sqlEdgeContainer.GetConnectionString();
return _postgreSqlContainer.GetConnectionString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<h1>Weather Forecast</h1>
<FluentDataGrid Items="@_weatherData.AsQueryable()">
<ChildContent>
<PropertyColumn Title="Date" Property="@(item => item.Date.ToShortDateString())"/>
<PropertyColumn Title="Period" Property="@(item => item.Period.Date.ToShortDateString())"/>
<PropertyColumn Title="Avg °C" Property="@(item => item.Temperatures.Average(temperature => temperature.Value).ToString("0"))"/>
</ChildContent>
<EmptyContent></EmptyContent>
Expand Down
4 changes: 2 additions & 2 deletions examples/WeatherForecast/src/WeatherForecast/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
builder.Services.AddDbContext<WeatherDataContext>((services, options) =>
{
var databaseContainer = services.GetRequiredService<DatabaseContainer>();
options.UseSqlServer(databaseContainer.GetConnectionString());
options.UseNpgsql(databaseContainer.GetConnectionString());
});
}
else
{
// The application configuration includes a database connection string, use it to establish a connection and seed the database.
builder.Services.AddDbContext<WeatherDataContext>((_, options) => options.UseSqlServer(connectionString));
builder.Services.AddDbContext<WeatherDataContext>((_, options) => options.UseNpgsql(connectionString));
}

builder.Services.AddScoped<IWeatherDataReadOnlyRepository, WeatherDataReadOnlyContext>();
Expand Down
2 changes: 1 addition & 1 deletion examples/WeatherForecast/src/WeatherForecast/Usings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Fast.Components.FluentUI;
global using Testcontainers.SqlEdge;
global using Testcontainers.PostgreSql;
global using WeatherForecast;
global using WeatherForecast.Contexts;
global using WeatherForecast.Entities;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer"/>
<PackageReference Include="Microsoft.Fast.Components.FluentUI"/>
<PackageReference Include="Testcontainers.SqlEdge"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL"/>
<PackageReference Include="Testcontainers.PostgreSql"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../WeatherForecast.Contexts/WeatherForecast.Contexts.csproj"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
global using JetBrains.Annotations;
global using Microsoft.AspNetCore.Mvc.Testing;
global using Microsoft.Extensions.DependencyInjection;
global using Testcontainers.SqlEdge;
global using Testcontainers.PostgreSql;
global using WeatherForecast.Entities;
global using WeatherForecast.Repositories;
global using Xunit;
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ namespace WeatherForecast.InProcess.Tests;
[UsedImplicitly]
public sealed class WeatherForecastTest : IAsyncLifetime
{
private readonly SqlEdgeContainer _sqlEdgeContainer = new SqlEdgeBuilder().Build();
private readonly PostgreSqlContainer _postgreSqlContainer = new PostgreSqlBuilder().Build();

public Task InitializeAsync()
{
return _sqlEdgeContainer.StartAsync();
return _postgreSqlContainer.StartAsync();
}

public Task DisposeAsync()
{
return _sqlEdgeContainer.DisposeAsync().AsTask();
return _postgreSqlContainer.DisposeAsync().AsTask();
}

public sealed class Api : IClassFixture<WeatherForecastTest>, IDisposable
Expand All @@ -30,7 +30,7 @@ public Api(WeatherForecastTest weatherForecastTest)
Environment.SetEnvironmentVariable("ASPNETCORE_URLS", "https://+");
Environment.SetEnvironmentVariable("ASPNETCORE_Kestrel__Certificates__Default__Path", "certificate.crt");
Environment.SetEnvironmentVariable("ASPNETCORE_Kestrel__Certificates__Default__Password", "password");
Environment.SetEnvironmentVariable("ConnectionStrings__DefaultConnection", weatherForecastTest._sqlEdgeContainer.GetConnectionString());
Environment.SetEnvironmentVariable("ConnectionStrings__DefaultConnection", weatherForecastTest._postgreSqlContainer.GetConnectionString());
_webApplicationFactory = new WebApplicationFactory<Program>();
_serviceScope = _webApplicationFactory.Services.GetRequiredService<IServiceScopeFactory>().CreateScope();
_httpClient = _webApplicationFactory.CreateClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
global using DotNet.Testcontainers.Images;
global using DotNet.Testcontainers.Networks;
global using JetBrains.Annotations;
global using Testcontainers.SqlEdge;
global using Testcontainers.PostgreSql;
global using WeatherForecast.Entities;
global using Xunit;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public sealed class WeatherForecastContainer : HttpClient, IAsyncLifetime

private readonly INetwork _weatherForecastNetwork;

private readonly IContainer _sqlEdgeContainer;
private readonly IContainer _postgreSqlContainer;

private readonly IContainer _weatherForecastContainer;

Expand All @@ -22,12 +22,12 @@ public WeatherForecastContainer()
{
const string weatherForecastStorage = "weatherForecastStorage";

const string connectionString = $"Server={weatherForecastStorage};User Id={SqlEdgeBuilder.DefaultUsername};Password={SqlEdgeBuilder.DefaultPassword};Database={SqlEdgeBuilder.DefaultDatabase};TrustServerCertificate=True";
const string connectionString = $"Host={weatherForecastStorage};Username={PostgreSqlBuilder.DefaultUsername};Password={PostgreSqlBuilder.DefaultPassword};Database={PostgreSqlBuilder.DefaultDatabase}";

_weatherForecastNetwork = new NetworkBuilder()
.Build();

_sqlEdgeContainer = new SqlEdgeBuilder()
_postgreSqlContainer = new PostgreSqlBuilder()
.WithNetwork(_weatherForecastNetwork)
.WithNetworkAliases(weatherForecastStorage)
.Build();
Expand All @@ -52,7 +52,7 @@ await Image.InitializeAsync()
await _weatherForecastNetwork.CreateAsync()
.ConfigureAwait(false);

await _sqlEdgeContainer.StartAsync()
await _postgreSqlContainer.StartAsync()
.ConfigureAwait(false);

await _weatherForecastContainer.StartAsync()
Expand All @@ -68,7 +68,7 @@ await Image.DisposeAsync()
await _weatherForecastContainer.DisposeAsync()
.ConfigureAwait(false);

await _sqlEdgeContainer.DisposeAsync()
await _postgreSqlContainer.DisposeAsync()
.ConfigureAwait(false);

await _weatherForecastNetwork.DeleteAsync()
Expand Down

0 comments on commit 136ca49

Please sign in to comment.