Skip to content

Commit 6e92a9f

Browse files
committed
fix(#126): implicitly add db context to context graph
1 parent 93b063e commit 6e92a9f

File tree

4 files changed

+69
-19
lines changed

4 files changed

+69
-19
lines changed

src/JsonApiDotNetCore/Builders/ContextGraphBuilder.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
using JsonApiDotNetCore.Internal;
66
using JsonApiDotNetCore.Models;
77
using JsonApiDotNetCore.Extensions;
8+
using System.Linq;
89

910
namespace JsonApiDotNetCore.Builders
1011
{
1112
public class ContextGraphBuilder : IContextGraphBuilder
1213
{
13-
private List<ContextEntity> _entities;
14+
private List<ContextEntity> _entities = new List<ContextEntity>();
1415
private bool _usesDbContext;
1516
public Link DocumentLinks { get; set; } = Link.All;
1617

@@ -32,6 +33,9 @@ public IContextGraph Build()
3233
public void AddResource<TResource>(string pluralizedTypeName) where TResource : class
3334
{
3435
var entityType = typeof(TResource);
36+
37+
VerifyEntityIsNotAlreadyDefined(entityType);
38+
3539
_entities.Add(new ContextEntity
3640
{
3741
EntityName = pluralizedTypeName,
@@ -98,8 +102,6 @@ public void AddDbContext<T>() where T : DbContext
98102

99103
var contextType = typeof(T);
100104

101-
var entities = new List<ContextEntity>();
102-
103105
var contextProperties = contextType.GetProperties();
104106

105107
foreach (var property in contextProperties)
@@ -110,7 +112,10 @@ public void AddDbContext<T>() where T : DbContext
110112
&& dbSetType.GetGenericTypeDefinition() == typeof(DbSet<>))
111113
{
112114
var entityType = dbSetType.GetGenericArguments()[0];
113-
entities.Add(new ContextEntity
115+
116+
VerifyEntityIsNotAlreadyDefined(entityType);
117+
118+
_entities.Add(new ContextEntity
114119
{
115120
EntityName = GetResourceName(property),
116121
EntityType = entityType,
@@ -119,8 +124,6 @@ public void AddDbContext<T>() where T : DbContext
119124
});
120125
}
121126
}
122-
123-
_entities = entities;
124127
}
125128

126129
private string GetResourceName(PropertyInfo property)
@@ -131,5 +134,11 @@ private string GetResourceName(PropertyInfo property)
131134

132135
return ((ResourceAttribute)resourceAttribute).ResourceName;
133136
}
137+
138+
private void VerifyEntityIsNotAlreadyDefined(Type entityType)
139+
{
140+
if (_entities.Any(e => e.EntityType == entityType))
141+
throw new InvalidOperationException($"Cannot add entity type {entityType} to context graph, there is already an entity of that type configured.");
142+
}
134143
}
135144
}

src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,28 @@ public class JsonApiOptions
1313
public int DefaultPageSize { get; set; }
1414
public bool IncludeTotalRecordCount { get; set; }
1515
public bool AllowClientGeneratedIds { get; set; }
16-
public IContextGraph ContextGraph { get; set; }
17-
public IContractResolver JsonContractResolver { get; set; } = new DasherizedResolver();
16+
public IContextGraph ContextGraph { get; set; }
17+
public IContractResolver JsonContractResolver { get; set; } = new DasherizedResolver();
18+
internal IContextGraphBuilder ContextGraphBuilder { get; } = new ContextGraphBuilder();
1819

1920
public void BuildContextGraph<TContext>(Action<IContextGraphBuilder> builder)
2021
where TContext : DbContext
2122
{
22-
var contextGraphBuilder = new ContextGraphBuilder();
23-
24-
contextGraphBuilder.AddDbContext<TContext>();
23+
BuildContextGraph(builder);
2524

26-
builder?.Invoke(contextGraphBuilder);
25+
ContextGraphBuilder.AddDbContext<TContext>();
2726

28-
ContextGraph = contextGraphBuilder.Build();
27+
ContextGraph = ContextGraphBuilder.Build();
2928
}
3029

3130
public void BuildContextGraph(Action<IContextGraphBuilder> builder)
3231
{
33-
if(builder == null)
32+
if (builder == null)
3433
throw new ArgumentException("Cannot build non-EF context graph without an IContextGraphBuilder action", nameof(builder));
3534

36-
var contextGraphBuilder = new ContextGraphBuilder();
35+
builder(ContextGraphBuilder);
3736

38-
builder(contextGraphBuilder);
39-
40-
ContextGraph = contextGraphBuilder.Build();
37+
ContextGraph = ContextGraphBuilder.Build();
4138
}
4239
}
4340
}

src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public static void AddJsonApi<TContext>(this IServiceCollection services,
4040

4141
options(config);
4242

43+
config.BuildContextGraph(builder => builder.AddDbContext<TContext>());
44+
4345
mvcBuilder
4446
.AddMvcOptions(opt =>
4547
{
@@ -83,7 +85,7 @@ public static void AddJsonApiInternals(
8385
this IServiceCollection services,
8486
JsonApiOptions jsonApiOptions)
8587
{
86-
if(!jsonApiOptions.ContextGraph.UsesDbContext)
88+
if (!jsonApiOptions.ContextGraph.UsesDbContext)
8789
{
8890
services.AddScoped<DbContext>();
8991
services.AddSingleton<DbContextOptions>(new DbContextOptionsBuilder().Options);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using JsonApiDotNetCore.Extensions;
3+
using JsonApiDotNetCore.Internal;
4+
using JsonApiDotNetCore.Models;
5+
using Microsoft.EntityFrameworkCore;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Moq;
8+
using Xunit;
9+
10+
namespace UnitTests
11+
{
12+
public class ContextGraphBuilder_Tests
13+
{
14+
class NonDbResource : Identifiable {}
15+
class DbResource : Identifiable {}
16+
class TestContext : DbContext {
17+
public DbSet<DbResource> DbResources { get; set; }
18+
}
19+
20+
[Fact]
21+
public void Can_Build_ContextGraph_Using_Builder()
22+
{
23+
// arrange
24+
var services = new ServiceCollection();
25+
services.AddJsonApi<TestContext>(opt => {
26+
opt.BuildContextGraph(b => {
27+
b.AddResource<NonDbResource>("non-db-resources");
28+
});
29+
});
30+
31+
// act
32+
var container = services.BuildServiceProvider();
33+
34+
// assert
35+
var contextGraph = container.GetRequiredService<IContextGraph>();
36+
var dbResource = contextGraph.GetContextEntity("db-resources").EntityType;
37+
var nonDbResource = contextGraph.GetContextEntity("non-db-resources").EntityType;
38+
Assert.Equal(typeof(DbResource), dbResource);
39+
Assert.Equal(typeof(NonDbResource), nonDbResource);
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)