Skip to content

Commit 3bf9157

Browse files
committed
Use ModelBuilder in sample to not depend on EF Core internals, build once at startup
1 parent f955b08 commit 3bf9157

9 files changed

+68
-70
lines changed

src/Examples/NoEntityFrameworkExample/Data/InMemoryModel.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.Reflection;
2+
using JsonApiDotNetCore.Configuration;
3+
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.EntityFrameworkCore.Metadata;
5+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
6+
7+
namespace NoEntityFrameworkExample.Data;
8+
9+
internal static class ResourceGraphExtensions
10+
{
11+
public static IReadOnlyModel ToEntityModel(this IResourceGraph resourceGraph)
12+
{
13+
var modelBuilder = new ModelBuilder();
14+
15+
foreach (ResourceType resourceType in resourceGraph.GetResourceTypes())
16+
{
17+
IncludeResourceType(resourceType, modelBuilder);
18+
}
19+
20+
return modelBuilder.Model;
21+
}
22+
23+
private static void IncludeResourceType(ResourceType resourceType, ModelBuilder builder)
24+
{
25+
EntityTypeBuilder entityTypeBuilder = builder.Entity(resourceType.ClrType);
26+
27+
foreach (PropertyInfo property in resourceType.ClrType.GetProperties())
28+
{
29+
entityTypeBuilder.Property(property.PropertyType, property.Name);
30+
}
31+
}
32+
}

src/Examples/NoEntityFrameworkExample/Program.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using JsonApiDotNetCore.Configuration;
22
using NoEntityFrameworkExample;
3+
using NoEntityFrameworkExample.Data;
34

45
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
56

@@ -20,6 +21,12 @@
2021
#endif
2122
}, discovery => discovery.AddCurrentAssembly());
2223

24+
builder.Services.AddSingleton(serviceProvider =>
25+
{
26+
var resourceGraph = serviceProvider.GetRequiredService<IResourceGraph>();
27+
return resourceGraph.ToEntityModel();
28+
});
29+
2330
WebApplication app = builder.Build();
2431

2532
// Configure the HTTP request pipeline.

src/Examples/NoEntityFrameworkExample/Repositories/InMemoryResourceRepository.cs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using JsonApiDotNetCore.Queries.QueryableBuilding;
55
using JsonApiDotNetCore.Repositories;
66
using JsonApiDotNetCore.Resources;
7-
using NoEntityFrameworkExample.Data;
7+
using Microsoft.EntityFrameworkCore.Metadata;
88

99
namespace NoEntityFrameworkExample.Repositories;
1010

@@ -19,19 +19,12 @@ namespace NoEntityFrameworkExample.Repositories;
1919
/// <typeparam name="TId">
2020
/// The resource identifier type.
2121
/// </typeparam>
22-
public abstract class InMemoryResourceRepository<TResource, TId> : IResourceReadRepository<TResource, TId>
22+
public abstract class InMemoryResourceRepository<TResource, TId>(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder, IReadOnlyModel entityModel)
23+
: IResourceReadRepository<TResource, TId>
2324
where TResource : class, IIdentifiable<TId>
2425
{
25-
private readonly ResourceType _resourceType;
26-
private readonly QueryLayerToLinqConverter _queryLayerToLinqConverter;
27-
28-
protected InMemoryResourceRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder)
29-
{
30-
_resourceType = resourceGraph.GetResourceType<TResource>();
31-
32-
var model = new InMemoryModel(resourceGraph);
33-
_queryLayerToLinqConverter = new QueryLayerToLinqConverter(model, queryableBuilder);
34-
}
26+
private readonly ResourceType _resourceType = resourceGraph.GetResourceType<TResource>();
27+
private readonly QueryLayerToLinqConverter _queryLayerToLinqConverter = new(entityModel, queryableBuilder);
3528

3629
/// <inheritdoc />
3730
public Task<IReadOnlyCollection<TResource>> GetAsync(QueryLayer queryLayer, CancellationToken cancellationToken)

src/Examples/NoEntityFrameworkExample/Repositories/PersonRepository.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
using JetBrains.Annotations;
22
using JsonApiDotNetCore.Configuration;
33
using JsonApiDotNetCore.Queries.QueryableBuilding;
4+
using Microsoft.EntityFrameworkCore.Metadata;
45
using NoEntityFrameworkExample.Data;
56
using NoEntityFrameworkExample.Models;
67

78
namespace NoEntityFrameworkExample.Repositories;
89

910
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
10-
public sealed class PersonRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder)
11-
: InMemoryResourceRepository<Person, long>(resourceGraph, queryableBuilder)
11+
public sealed class PersonRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder, IReadOnlyModel entityModel)
12+
: InMemoryResourceRepository<Person, long>(resourceGraph, queryableBuilder, entityModel)
1213
{
1314
protected override IEnumerable<Person> GetDataSource()
1415
{

src/Examples/NoEntityFrameworkExample/Repositories/TagRepository.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
using JetBrains.Annotations;
22
using JsonApiDotNetCore.Configuration;
33
using JsonApiDotNetCore.Queries.QueryableBuilding;
4+
using Microsoft.EntityFrameworkCore.Metadata;
45
using NoEntityFrameworkExample.Data;
56
using NoEntityFrameworkExample.Models;
67

78
namespace NoEntityFrameworkExample.Repositories;
89

910
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
10-
public sealed class TagRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder)
11-
: InMemoryResourceRepository<Tag, long>(resourceGraph, queryableBuilder)
11+
public sealed class TagRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder, IReadOnlyModel entityModel)
12+
: InMemoryResourceRepository<Tag, long>(resourceGraph, queryableBuilder, entityModel)
1213
{
1314
protected override IEnumerable<Tag> GetDataSource()
1415
{

src/Examples/NoEntityFrameworkExample/Repositories/TodoItemRepository.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
using JetBrains.Annotations;
22
using JsonApiDotNetCore.Configuration;
33
using JsonApiDotNetCore.Queries.QueryableBuilding;
4+
using Microsoft.EntityFrameworkCore.Metadata;
45
using NoEntityFrameworkExample.Data;
56
using NoEntityFrameworkExample.Models;
67

78
namespace NoEntityFrameworkExample.Repositories;
89

910
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
10-
public sealed class TodoItemRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder)
11-
: InMemoryResourceRepository<TodoItem, long>(resourceGraph, queryableBuilder)
11+
public sealed class TodoItemRepository(IResourceGraph resourceGraph, IQueryableBuilder queryableBuilder, IReadOnlyModel entityModel)
12+
: InMemoryResourceRepository<TodoItem, long>(resourceGraph, queryableBuilder, entityModel)
1213
{
1314
protected override IEnumerable<TodoItem> GetDataSource()
1415
{

src/Examples/NoEntityFrameworkExample/Services/InMemoryResourceService.cs

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using JsonApiDotNetCore.Resources;
88
using JsonApiDotNetCore.Resources.Annotations;
99
using JsonApiDotNetCore.Services;
10-
using NoEntityFrameworkExample.Data;
10+
using Microsoft.EntityFrameworkCore.Metadata;
1111

1212
namespace NoEntityFrameworkExample.Services;
1313

@@ -30,32 +30,19 @@ namespace NoEntityFrameworkExample.Services;
3030
/// <typeparam name="TId">
3131
/// The resource identifier type.
3232
/// </typeparam>
33-
public abstract class InMemoryResourceService<TResource, TId> : IResourceQueryService<TResource, TId>
33+
public abstract class InMemoryResourceService<TResource, TId>(
34+
IJsonApiOptions options, IResourceGraph resourceGraph, IQueryLayerComposer queryLayerComposer, IPaginationContext paginationContext,
35+
IEnumerable<IQueryConstraintProvider> constraintProviders, IQueryableBuilder queryableBuilder, IReadOnlyModel entityModel,
36+
ILoggerFactory loggerFactory) : IResourceQueryService<TResource, TId>
3437
where TResource : class, IIdentifiable<TId>
3538
{
36-
private readonly IJsonApiOptions _options;
37-
private readonly IQueryLayerComposer _queryLayerComposer;
38-
private readonly IPaginationContext _paginationContext;
39-
private readonly IEnumerable<IQueryConstraintProvider> _constraintProviders;
40-
private readonly ILogger<InMemoryResourceService<TResource, TId>> _logger;
41-
private readonly ResourceType _resourceType;
42-
private readonly QueryLayerToLinqConverter _queryLayerToLinqConverter;
43-
44-
protected InMemoryResourceService(IJsonApiOptions options, IResourceGraph resourceGraph, IQueryLayerComposer queryLayerComposer,
45-
IPaginationContext paginationContext, IEnumerable<IQueryConstraintProvider> constraintProviders, IQueryableBuilder queryableBuilder,
46-
ILoggerFactory loggerFactory)
47-
{
48-
_options = options;
49-
_queryLayerComposer = queryLayerComposer;
50-
_paginationContext = paginationContext;
51-
_constraintProviders = constraintProviders;
52-
53-
_logger = loggerFactory.CreateLogger<InMemoryResourceService<TResource, TId>>();
54-
_resourceType = resourceGraph.GetResourceType<TResource>();
55-
56-
var model = new InMemoryModel(resourceGraph);
57-
_queryLayerToLinqConverter = new QueryLayerToLinqConverter(model, queryableBuilder);
58-
}
39+
private readonly IJsonApiOptions _options = options;
40+
private readonly IQueryLayerComposer _queryLayerComposer = queryLayerComposer;
41+
private readonly IPaginationContext _paginationContext = paginationContext;
42+
private readonly IEnumerable<IQueryConstraintProvider> _constraintProviders = constraintProviders;
43+
private readonly ILogger<InMemoryResourceService<TResource, TId>> _logger = loggerFactory.CreateLogger<InMemoryResourceService<TResource, TId>>();
44+
private readonly ResourceType _resourceType = resourceGraph.GetResourceType<TResource>();
45+
private readonly QueryLayerToLinqConverter _queryLayerToLinqConverter = new(entityModel, queryableBuilder);
5946

6047
/// <inheritdoc />
6148
public Task<IReadOnlyCollection<TResource>> GetAsync(CancellationToken cancellationToken)

src/Examples/NoEntityFrameworkExample/Services/TodoItemService.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using JsonApiDotNetCore.Queries;
44
using JsonApiDotNetCore.Queries.QueryableBuilding;
55
using JsonApiDotNetCore.Resources;
6+
using Microsoft.EntityFrameworkCore.Metadata;
67
using NoEntityFrameworkExample.Data;
78
using NoEntityFrameworkExample.Models;
89

@@ -11,8 +12,8 @@ namespace NoEntityFrameworkExample.Services;
1112
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
1213
public sealed class TodoItemService(
1314
IJsonApiOptions options, IResourceGraph resourceGraph, IQueryLayerComposer queryLayerComposer, IPaginationContext paginationContext,
14-
IEnumerable<IQueryConstraintProvider> constraintProviders, IQueryableBuilder queryableBuilder, ILoggerFactory loggerFactory)
15-
: InMemoryResourceService<TodoItem, long>(options, resourceGraph, queryLayerComposer, paginationContext, constraintProviders, queryableBuilder,
15+
IEnumerable<IQueryConstraintProvider> constraintProviders, IQueryableBuilder queryableBuilder, IReadOnlyModel entityModel, ILoggerFactory loggerFactory)
16+
: InMemoryResourceService<TodoItem, long>(options, resourceGraph, queryLayerComposer, paginationContext, constraintProviders, queryableBuilder, entityModel,
1617
loggerFactory)
1718
{
1819
protected override IEnumerable<IIdentifiable> GetDataSource(ResourceType resourceType)

0 commit comments

Comments
 (0)