Skip to content

Commit 3b6b9dc

Browse files
committed
Update Issue12PostgreSql sample to use .NET 10x
1 parent 6d74c8d commit 3b6b9dc

20 files changed

Lines changed: 382 additions & 421 deletions

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<VersionPrefix>5.3.6</VersionPrefix>
3+
<VersionPrefix>5.3.7</VersionPrefix>
44
<LangVersion>latest</LangVersion>
55
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
66
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<PackageVersion Include="IDisposableAnalyzers" Version="4.0.8" />
3030
</ItemGroup>
3131
<ItemGroup>
32-
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.264" />
32+
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.266" />
3333
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.17.0.131074" />
3434
<PackageVersion Include="Microsoft.EntityFrameworkCore.Analyzers" Version="10.0.0" />
3535
</ItemGroup>

EFCoreSecondLevelCacheInterceptor.slnx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<Project Path="src/Tests/Issues/Issue123WithMessagePack/Issue123WithMessagePack.csproj" />
2828
<Project Path="src/Tests/Issues/Issue125EF5x/Issue125EF5x.csproj" />
2929
<Project Path="src/Tests/Issues/Issue12MySQL/Issue12MySQL.csproj" />
30-
<!--<Project Path="src/Tests/Issues/Issue12PostgreSql/Issue12PostgreSql.csproj" />-->
30+
<Project Path="src/Tests/Issues/Issue12PostgreSql/Issue12PostgreSql.csproj" />
3131
<Project Path="src/Tests/Issues/Issue154/Issue154.csproj" />
3232
<!--<Project Path="src/Tests/Issues/Issue192/Issue192.csproj" />-->
3333
<Project Path="src/Tests/Issues/Issue4SpatialType/Issue4SpatialType.csproj" />

src/EFCoreSecondLevelCacheInterceptor/EFTableRowsDataReader.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,11 @@ public override T GetFieldValue<T>(int ordinal)
587587
return (T)(object)DateOnly.Parse((string)value, CultureInfo.InvariantCulture);
588588
}
589589

590+
if (expectedValueType == TypeExtensions.DateOnlyType && isActualValueTypeNumber)
591+
{
592+
return (T)(object)DateOnly.FromDateTime(new DateTime(Convert.ToInt64(value, CultureInfo.InvariantCulture)));
593+
}
594+
590595
if (expectedValueType == TypeExtensions.TimeOnlyType && actualValueType == TypeExtensions.TimeSpanType)
591596
{
592597
return (T)(object)TimeOnly.FromTimeSpan((TimeSpan)value);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using MessagePack;
2+
using MessagePack.Formatters;
3+
4+
namespace Issue12PostgreSql;
5+
6+
public class DBNullFormatter : IMessagePackFormatter<DBNull?>
7+
{
8+
public static readonly DBNullFormatter Instance = new();
9+
10+
private DBNullFormatter()
11+
{
12+
}
13+
14+
public void Serialize(ref MessagePackWriter writer, DBNull? value, MessagePackSerializerOptions options)
15+
=> writer.WriteNil();
16+
17+
public DBNull? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) => DBNull.Value;
18+
}
Lines changed: 6 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,26 @@
11
using Issue12PostgreSql.Entities;
22
using Microsoft.EntityFrameworkCore;
3-
using Microsoft.Extensions.Logging;
43

54
namespace Issue12PostgreSql.DataLayer;
65

76
public class ApplicationDbContext : DbContext
87
{
9-
public ApplicationDbContext(DbContextOptions options)
10-
: base(options)
8+
public ApplicationDbContext(DbContextOptions options) : base(options)
119
{
1210
}
1311

1412
public DbSet<Person> People { get; set; }
13+
1514
public DbSet<Address> Addresses { get; set; }
15+
1616
public DbSet<Book> Books { get; set; }
17+
1718
public DbSet<Entity> Entities { get; set; }
1819

1920
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
2021
{
21-
optionsBuilder
22-
.UseLoggerFactory(LoggerFactory.Create(x => x
23-
.AddConsole()
24-
.AddFilter(y => y >= LogLevel.Debug)))
25-
.EnableSensitiveDataLogging()
26-
.EnableDetailedErrors();
22+
optionsBuilder.EnableSensitiveDataLogging().EnableDetailedErrors();
2723

2824
base.OnConfiguring(optionsBuilder);
2925
}
30-
31-
protected override void OnModelCreating(ModelBuilder builder)
32-
{
33-
base.OnModelCreating(builder);
34-
35-
/*foreach (var property in builder.Model.GetEntityTypes()
36-
.SelectMany(t => t.GetProperties())
37-
.Where(p => p.GetColumnType() == "jsonb"))
38-
{
39-
var converterType = typeof(JsonbConvertor<>).MakeGenericType(property.ClrType);
40-
var converter = (ValueConverter)Activator.CreateInstance(converterType, (object)null);
41-
property.SetValueConverter(converter);
42-
}*/
43-
44-
// It does not support DateTimeOffset
45-
/*foreach (var property in builder.Model.GetEntityTypes()
46-
.SelectMany(t => t.GetProperties())
47-
.Where(p => p.ClrType == typeof(DateTimeOffset)))
48-
{
49-
property.SetValueConverter(
50-
new ValueConverter<DateTimeOffset, DateTime>(
51-
convertToProviderExpression: dateTimeOffset => dateTimeOffset.UtcDateTime,
52-
convertFromProviderExpression: dateTime => new DateTimeOffset(dateTime)
53-
));
54-
}
55-
56-
foreach (var property in builder.Model.GetEntityTypes()
57-
.SelectMany(t => t.GetProperties())
58-
.Where(p => p.ClrType == typeof(DateTimeOffset?)))
59-
{
60-
property.SetValueConverter(
61-
new ValueConverter<DateTimeOffset?, DateTime>(
62-
convertToProviderExpression: dateTimeOffset => dateTimeOffset.Value.UtcDateTime,
63-
convertFromProviderExpression: dateTime => new DateTimeOffset(dateTime)
64-
));
65-
}*/
66-
67-
// Supporting DateOnly
68-
/*foreach (var property in builder.Model.GetEntityTypes()
69-
.SelectMany(t => t.GetProperties())
70-
.Where(p => p.ClrType == typeof(DateOnly)))
71-
{
72-
property.SetValueConverter(
73-
new ValueConverter<DateOnly, DateTime>(
74-
convertToProviderExpression: dateOnly => dateOnly.ToDateTime(new TimeOnly(0, 0)),
75-
convertFromProviderExpression: dateTime => DateOnly.FromDateTime(dateTime)
76-
));
77-
}
78-
79-
foreach (var property in builder.Model.GetEntityTypes()
80-
.SelectMany(t => t.GetProperties())
81-
.Where(p => p.ClrType == typeof(DateOnly?)))
82-
{
83-
property.SetValueConverter(
84-
new ValueConverter<DateOnly?, DateTime>(
85-
convertToProviderExpression: dateOnly => dateOnly.Value.ToDateTime(new TimeOnly(0, 0)),
86-
convertFromProviderExpression: dateTime => DateOnly.FromDateTime(dateTime)
87-
));
88-
}*/
89-
90-
// Supporting TimeOnly
91-
/*foreach (var property in builder.Model.GetEntityTypes()
92-
.SelectMany(t => t.GetProperties())
93-
.Where(p => p.ClrType == typeof(TimeOnly)))
94-
{
95-
property.SetValueConverter(
96-
new ValueConverter<TimeOnly, TimeSpan>(
97-
convertToProviderExpression: timeOnly => timeOnly.ToTimeSpan(),
98-
convertFromProviderExpression: timeSpan => TimeOnly.FromTimeSpan(timeSpan)
99-
));
100-
}
101-
102-
foreach (var property in builder.Model.GetEntityTypes()
103-
.SelectMany(t => t.GetProperties())
104-
.Where(p => p.ClrType == typeof(TimeOnly?)))
105-
{
106-
property.SetValueConverter(
107-
new ValueConverter<TimeOnly?, TimeSpan>(
108-
convertToProviderExpression: timeOnly => timeOnly.Value.ToTimeSpan(),
109-
convertFromProviderExpression: timeSpan => TimeOnly.FromTimeSpan(timeSpan)
110-
));
111-
}*/
112-
}
113-
}
114-
115-
/*public class JsonbConvertor<T> : ValueConverter<T, string>
116-
{
117-
private static readonly Expression<Func<T, string>> _convertToProviderExpression = x => Serialize(x);
118-
private static readonly Expression<Func<string, T>> _convertFromProviderExpression = x => Deserialize(x);
119-
120-
public JsonbConvertor(ConverterMappingHints mappingHints = null)
121-
: base(_convertToProviderExpression, _convertFromProviderExpression, mappingHints)
122-
{ }
123-
124-
private static string Serialize(T x)
125-
{
126-
return JsonSerializer.Serialize(x);
127-
}
128-
129-
private static T Deserialize(string x)
130-
{
131-
return JsonSerializer.Deserialize<T>(x);
132-
}
133-
}*/
26+
}
Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
1-
using Microsoft.EntityFrameworkCore.Design;
21
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.EntityFrameworkCore.Design;
33
using Microsoft.Extensions.Configuration;
4-
using System;
5-
using System.IO;
64
using Microsoft.Extensions.DependencyInjection;
75

8-
namespace Issue12PostgreSql.DataLayer
6+
namespace Issue12PostgreSql.DataLayer;
7+
8+
public class NpgSqlContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
99
{
10-
public class NpgSqlContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
10+
public ApplicationDbContext CreateDbContext(string[] args)
1111
{
12-
public ApplicationDbContext CreateDbContext(string[] args)
13-
{
14-
var services = new ServiceCollection();
12+
var services = new ServiceCollection();
13+
14+
var basePath = Directory.GetCurrentDirectory();
15+
Console.WriteLine($"Using `{basePath}` as the ContentRootPath");
16+
17+
var configuration = new ConfigurationBuilder().SetBasePath(basePath)
18+
.AddJsonFile(path: "appsettings.json", optional: false, reloadOnChange: true)
19+
.Build();
20+
21+
services.AddSingleton(_ => configuration);
1522

16-
var basePath = Directory.GetCurrentDirectory();
17-
Console.WriteLine($"Using `{basePath}` as the ContentRootPath");
18-
var configuration = new ConfigurationBuilder()
19-
.SetBasePath(basePath)
20-
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
21-
.Build();
22-
services.AddSingleton(_ => configuration);
23+
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
24+
optionsBuilder.UseNpgsql(configuration[key: "ConnectionStrings:ApplicationDbContextConnection"]);
2325

24-
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
25-
optionsBuilder.UseNpgsql(configuration["ConnectionStrings:ApplicationDbContextConnection"]);
26-
return new ApplicationDbContext(optionsBuilder.Options);
27-
}
26+
return new ApplicationDbContext(optionsBuilder.Options);
2827
}
2928
}

src/Tests/Issues/Issue12PostgreSql/EFServiceProvider.cs

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
using System;
2-
using System.IO;
3-
using System.Threading;
4-
using System.Threading.Tasks;
51
using EasyCaching.Core.Configurations;
62
using EFCoreSecondLevelCacheInterceptor;
73
using Issue12PostgreSql.DataLayer;
84
using MessagePack;
95
using MessagePack.Formatters;
106
using MessagePack.Resolvers;
117
using Microsoft.EntityFrameworkCore;
8+
using Microsoft.Extensions.Caching.Hybrid;
129
using Microsoft.Extensions.Configuration;
1310
using Microsoft.Extensions.DependencyInjection;
1411
using Microsoft.Extensions.Logging;
12+
using Npgsql;
1513

1614
namespace Issue12PostgreSql;
1715

@@ -26,6 +24,7 @@ public static class EFServiceProvider
2624
public static IServiceProvider Instance { get; } = _serviceProviderBuilder.Value;
2725

2826
public static T GetRequiredService<T>()
27+
where T : notnull
2928
=> Instance.GetRequiredService<T>();
3029

3130
public static void RunInContext(Action<ApplicationDbContext> action)
@@ -53,7 +52,8 @@ private static IServiceProvider getServiceProvider()
5352
Console.WriteLine($"Using `{basePath}` as the ContentRootPath");
5453

5554
var configuration = new ConfigurationBuilder().SetBasePath(basePath)
56-
.AddJsonFile("appsettings.json", false, true).Build();
55+
.AddJsonFile(path: "appsettings.json", optional: false, reloadOnChange: true)
56+
.Build();
5757

5858
services.AddSingleton(_ => configuration);
5959

@@ -64,7 +64,7 @@ private static IServiceProvider getServiceProvider()
6464
o.UseRedis(cfg =>
6565
{
6666
cfg.SerializerName = "Pack";
67-
cfg.DBConfig.Endpoints.Add(new ServerEndPoint("127.0.0.1", 6379));
67+
cfg.DBConfig.Endpoints.Add(new ServerEndPoint(host: "127.0.0.1", port: 6379));
6868
cfg.DBConfig.AllowAdmin = true;
6969
cfg.DBConfig.ConnectionTimeout = 10000;
7070
}, providerName);
@@ -82,41 +82,44 @@ private static IServiceProvider getServiceProvider()
8282
StandardResolverAllowPrivate.Instance, TypelessContractlessStandardResolver.Instance,
8383
DynamicGenericResolver.Instance
8484
});
85-
}, "Pack");
85+
}, name: "Pack");
86+
});
87+
88+
services.AddHybridCache(options =>
89+
{
90+
options.DefaultEntryOptions = new HybridCacheEntryOptions
91+
{
92+
Expiration = TimeSpan.FromHours(hours: 1),
93+
LocalCacheExpiration = TimeSpan.FromHours(hours: 1)
94+
};
8695
});
8796

8897
services.AddEFSecondLevelCache(o =>
8998
{
90-
o.UseEasyCachingCoreProvider(providerName).ConfigureLogging(true);
91-
o.CacheAllQueries(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(10));
92-
o.UseCacheKeyPrefix("EF_");
99+
o.UseHybridCacheProvider(CacheExpirationMode.Absolute, TimeSpan.FromHours(hours: 1))
93100

94-
// Fallback on db if the caching provider (redis) is down.
95-
o.UseDbCallsIfCachingProviderIsDown(TimeSpan.FromMinutes(1));
101+
//.UseMemoryCacheProvider()
102+
//.UseEasyCachingCoreProvider(providerName).ConfigureLogging(enable: true)
103+
.CacheAllQueries(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(minutes: 10))
104+
.UseCacheKeyPrefix(prefix: "EF_")
105+
106+
// Fallback on db if the caching provider (redis) is down.
107+
.UseDbCallsIfCachingProviderIsDown(TimeSpan.FromMinutes(minutes: 1));
96108
});
97109

110+
#pragma warning disable IDISP001
111+
var dataSource =
112+
new NpgsqlDataSourceBuilder(configuration[key: "ConnectionStrings:ApplicationDbContextConnection"])
113+
.EnableDynamicJson()
114+
.Build();
115+
#pragma warning restore IDISP001
116+
98117
services.AddDbContext<ApplicationDbContext>((serviceProvider, optionsBuilder) =>
99118
{
100119
optionsBuilder.AddInterceptors(serviceProvider.GetRequiredService<SecondLevelCacheInterceptor>())
101-
.UseNpgsql(configuration["ConnectionStrings:ApplicationDbContextConnection"])
102-
.LogTo(sql => Console.WriteLine(sql));
120+
.UseNpgsql(dataSource);
103121
});
104122

105123
return services.BuildServiceProvider();
106124
}
107-
}
108-
109-
public class DBNullFormatter : IMessagePackFormatter<DBNull>
110-
{
111-
public static DBNullFormatter Instance = new();
112-
113-
private DBNullFormatter()
114-
{
115-
}
116-
117-
public void Serialize(ref MessagePackWriter writer, DBNull value, MessagePackSerializerOptions options)
118-
=> writer.WriteNil();
119-
120-
public DBNull Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
121-
=> DBNull.Value;
122125
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Issue12PostgreSql.Entities;
2+
3+
public class Address
4+
{
5+
public int Id { get; set; }
6+
7+
public required string Name { get; set; }
8+
9+
public Person Person { get; set; } = null!;
10+
11+
public int PersonId { get; set; }
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Issue12PostgreSql.Entities;
2+
3+
public class BlogOption
4+
{
5+
public bool IsActive { get; set; }
6+
7+
public int NumberOfTimesUsed { get; set; }
8+
9+
public int SortOrder { get; set; }
10+
11+
public required string Name { get; set; }
12+
}

0 commit comments

Comments
 (0)