Skip to content

Commit 85ee717

Browse files
committed
feat: remove GetInverseRelationship from ResourceGraph
1 parent baa77ee commit 85ee717

File tree

7 files changed

+50
-42
lines changed

7 files changed

+50
-42
lines changed

src/JsonApiDotNetCore/Hooks/Execution/HookExecutorHelper.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,15 @@ internal class HookExecutorHelper : IHookExecutorHelper
2222
private readonly IdentifiableComparer _comparer = new IdentifiableComparer();
2323
private readonly IJsonApiOptions _options;
2424
protected readonly IGenericProcessorFactory _genericProcessorFactory;
25-
protected readonly IResourceGraph _graph;
2625
protected readonly Dictionary<DependentType, IResourceHookContainer> _hookContainers;
2726
protected readonly Dictionary<DependentType, IHooksDiscovery> _hookDiscoveries;
2827
protected readonly List<ResourceHook> _targetedHooksForRelatedEntities;
2928

30-
public HookExecutorHelper(
31-
IGenericProcessorFactory genericProcessorFactory,
32-
IResourceGraph graph,
33-
IJsonApiOptions options
34-
)
29+
public HookExecutorHelper(IGenericProcessorFactory genericProcessorFactory,
30+
IJsonApiOptions options)
3531
{
3632
_options = options;
3733
_genericProcessorFactory = genericProcessorFactory;
38-
_graph = graph;
3934
_hookContainers = new Dictionary<DependentType, IResourceHookContainer>();
4035
_hookDiscoveries = new Dictionary<DependentType, IHooksDiscovery>();
4136
_targetedHooksForRelatedEntities = new List<ResourceHook>();

src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,19 @@ internal class ResourceHookExecutor : IResourceHookExecutor
2121
private readonly ITraversalHelper _traversalHelper;
2222
private readonly IIncludeService _includeService;
2323
private readonly ITargetedFields _targetedFields;
24-
private readonly IResourceGraph _graph;
24+
private readonly IInverseRelationships _inverseRelationships;
2525
public ResourceHookExecutor(
2626
IHookExecutorHelper executorHelper,
2727
ITraversalHelper traversalHelper,
2828
ITargetedFields targetedFields,
2929
IIncludeService includedRelationships,
30-
IResourceGraph resourceGraph)
30+
IInverseRelationships inverseRelationships)
3131
{
3232
_executorHelper = executorHelper;
3333
_traversalHelper = traversalHelper;
3434
_targetedFields = targetedFields;
3535
_includeService = includedRelationships;
36-
_graph = resourceGraph;
36+
_inverseRelationships = inverseRelationships;
3737
}
3838

3939
/// <inheritdoc/>
@@ -324,7 +324,7 @@ Dictionary<RelationshipAttribute, IEnumerable> ReplaceKeysWithInverseRelationshi
324324
/// If it isn't, JADNC currently knows nothing about this relationship pointing back, and it
325325
/// currently cannot fire hooks for entities resolved through inverse relationships.
326326
var inversableRelationshipAttributes = entitiesByRelationship.Where(kvp => kvp.Key.InverseNavigation != null);
327-
return inversableRelationshipAttributes.ToDictionary(kvp => _graph.GetInverseRelationship(kvp.Key), kvp => kvp.Value);
327+
return inversableRelationshipAttributes.ToDictionary(kvp => _inverseRelationships.GetInverse(kvp.Key), kvp => kvp.Value);
328328
}
329329

330330
/// <summary>
@@ -337,7 +337,7 @@ void FireForAffectedImplicits(Type entityTypeToInclude, Dictionary<RelationshipA
337337
if (container == null) return;
338338
var implicitAffected = _executorHelper.LoadImplicitlyAffected(implicitsTarget, existingImplicitEntities);
339339
if (!implicitAffected.Any()) return;
340-
var inverse = implicitAffected.ToDictionary(kvp => _graph.GetInverseRelationship(kvp.Key), kvp => kvp.Value);
340+
var inverse = implicitAffected.ToDictionary(kvp => _inverseRelationships.GetInverse(kvp.Key), kvp => kvp.Value);
341341
var resourcesByRelationship = CreateRelationshipHelper(entityTypeToInclude, inverse);
342342
CallHook(container, ResourceHook.BeforeImplicitUpdateRelationship, new object[] { resourcesByRelationship, pipeline, });
343343
}

src/JsonApiDotNetCore/Internal/Contracts/IContextEntityProvider.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ namespace JsonApiDotNetCore.Internal.Contracts
88
/// </summary>
99
public interface IContextEntityProvider
1010
{
11+
/// <summary>
12+
/// Gets all registered context entities
13+
/// </summary>
14+
ContextEntity[] GetContextEntities();
15+
1116
/// <summary>
1217
/// Get the resource metadata by the DbSet property name
1318
/// </summary>

src/JsonApiDotNetCore/Internal/Contracts/IResourceGraph.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,9 @@ namespace JsonApiDotNetCore.Internal.Contracts
44
{
55
/// <summary>
66
/// A cache for the models in entity core
7-
/// TODO: separate context entity getting part from relationship resolving part.
8-
/// These are two deviating responsibilities that often do not need to be exposed
9-
/// at the same time.
107
/// </summary>
118
public interface IResourceGraph : IContextEntityProvider
129
{
13-
RelationshipAttribute GetInverseRelationship(RelationshipAttribute relationship);
14-
1510
/// <summary>
1611
/// Was built against an EntityFrameworkCore DbContext ?
1712
/// </summary>

src/JsonApiDotNetCore/Internal/InverseRelationships.cs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq;
23
using JsonApiDotNetCore.Data;
34
using JsonApiDotNetCore.Internal.Contracts;
45
using JsonApiDotNetCore.Models;
@@ -24,28 +25,45 @@ public interface IInverseRelationships
2425
/// deal with resolving the inverse relationships.
2526
/// </summary>
2627
void Resolve();
28+
29+
30+
/// <summary>
31+
/// Traverses the resource graph for the inverse relationship of the provided
32+
/// <paramref name="relationship"/>;
33+
/// </summary>
34+
/// <param name="relationship"></param>
35+
RelationshipAttribute GetInverse(RelationshipAttribute relationship);
2736
}
2837

2938
/// <inheritdoc />
3039
public class InverseRelationships : IInverseRelationships
3140
{
32-
private readonly ResourceGraph _graph;
41+
private readonly IContextEntityProvider _provider;
3342
private readonly IDbContextResolver _resolver;
3443

35-
public InverseRelationships(IResourceGraph graph, IDbContextResolver resolver = null)
44+
public InverseRelationships(IContextEntityProvider provider, IDbContextResolver resolver = null)
3645
{
37-
_graph = (ResourceGraph)graph;
46+
_provider = (ResourceGraph)provider;
3847
_resolver = resolver;
3948
}
4049

50+
/// <inheritdoc />
51+
public RelationshipAttribute GetInverse(RelationshipAttribute relationship)
52+
{
53+
if (relationship.InverseNavigation == null) return null;
54+
return _provider.GetContextEntity(relationship.DependentType)
55+
.Relationships
56+
.SingleOrDefault(r => r.InternalRelationshipName == relationship.InverseNavigation);
57+
}
58+
4159
/// <inheritdoc />
4260
public void Resolve()
4361
{
4462
if (EntityFrameworkCoreIsEnabled())
4563
{
4664
DbContext context = _resolver.GetContext();
4765

48-
foreach (ContextEntity ce in _graph.Entities)
66+
foreach (ContextEntity ce in _provider.GetContextEntities())
4967
{
5068
IEntityType meta = context.Model.FindEntityType(ce.EntityType);
5169
if (meta == null) continue;
@@ -63,7 +81,6 @@ public void Resolve()
6381
/// If EF Core is not being used, we're expecting the resolver to not be registered.
6482
/// </summary>
6583
/// <returns><c>true</c>, if entity framework core was enabled, <c>false</c> otherwise.</returns>
66-
/// <param name="resolver">Resolver.</param>
6784
private bool EntityFrameworkCoreIsEnabled()
6885
{
6986
return _resolver != null;

src/JsonApiDotNetCore/Internal/ResourceGraph.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,8 @@ internal ResourceGraph(List<ContextEntity> entities, bool usesDbContext, List<Va
4747
/// <inheritdoc />
4848
public bool UsesDbContext { get; }
4949

50-
public RelationshipAttribute GetInverseRelationship(RelationshipAttribute relationship)
51-
{
52-
if (relationship.InverseNavigation == null) return null;
53-
return GetContextEntity(relationship.DependentType).Relationships.SingleOrDefault(r => r.InternalRelationshipName == relationship.InverseNavigation);
54-
}
50+
/// <inheritdoc />
51+
public ContextEntity[] GetContextEntities() => Entities.ToArray();
5552

5653
/// <inheritdoc />
5754
public ContextEntity GetContextEntity(string entityName)

test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,13 @@ protected List<TodoItem> CreateTodoWithOwner()
142142

143143
public class HooksTestsSetup : HooksDummyData
144144
{
145-
(IResourceGraph, Mock<ITargetedFields>, Mock<IIncludeService>, Mock<IGenericProcessorFactory>, IJsonApiOptions) CreateMocks()
145+
(IInverseRelationships, Mock<ITargetedFields>, Mock<IIncludeService>, Mock<IGenericProcessorFactory>, IJsonApiOptions) CreateMocks()
146146
{
147147
var pfMock = new Mock<IGenericProcessorFactory>();
148-
var graph = _graph;
149148
var ufMock = new Mock<ITargetedFields>();
150149
var iqsMock = new Mock<IIncludeService>();
151150
var optionsMock = new JsonApiOptions { LoaDatabaseValues = false };
152-
return (graph, ufMock, iqsMock, pfMock, optionsMock);
151+
return (new InverseRelationships(_graph), ufMock, iqsMock, pfMock, optionsMock);
153152
}
154153

155154
internal (Mock<IIncludeService>, ResourceHookExecutor, Mock<IResourceHookContainer<TMain>>) CreateTestObjects<TMain>(IHooksDiscovery<TMain> mainDiscovery = null)
@@ -159,13 +158,13 @@ public class HooksTestsSetup : HooksDummyData
159158
var mainResource = CreateResourceDefinition(mainDiscovery);
160159

161160
// mocking the GenericProcessorFactory and JsonApiContext and wiring them up.
162-
var (graph, ufMock, iqMock, gpfMock, options) = CreateMocks();
161+
var (inverse, ufMock, iqMock, gpfMock, options) = CreateMocks();
163162

164163
SetupProcessorFactoryForResourceDefinition(gpfMock, mainResource.Object, mainDiscovery, null);
165164

166-
var execHelper = new HookExecutorHelper(gpfMock.Object, graph, options);
167-
var traversalHelper = new TraversalHelper(graph, ufMock.Object);
168-
var hookExecutor = new ResourceHookExecutor(execHelper, traversalHelper, ufMock.Object, iqMock.Object, graph);
165+
var execHelper = new HookExecutorHelper(gpfMock.Object, options);
166+
var traversalHelper = new TraversalHelper(_graph, ufMock.Object);
167+
var hookExecutor = new ResourceHookExecutor(execHelper, traversalHelper, ufMock.Object, iqMock.Object, inverse);
169168

170169
return (iqMock, hookExecutor, mainResource);
171170
}
@@ -184,16 +183,16 @@ public class HooksTestsSetup : HooksDummyData
184183
var nestedResource = CreateResourceDefinition(nestedDiscovery);
185184

186185
// mocking the GenericProcessorFactory and JsonApiContext and wiring them up.
187-
var (graph, ufMock, iqMock, gpfMock, options) = CreateMocks();
186+
var (inverse, ufMock, iqMock, gpfMock, options) = CreateMocks();
188187

189188
var dbContext = repoDbContextOptions != null ? new AppDbContext(repoDbContextOptions) : null;
190189

191190
SetupProcessorFactoryForResourceDefinition(gpfMock, mainResource.Object, mainDiscovery, dbContext);
192191
SetupProcessorFactoryForResourceDefinition(gpfMock, nestedResource.Object, nestedDiscovery, dbContext);
193192

194-
var execHelper = new HookExecutorHelper(gpfMock.Object, graph, options);
195-
var traversalHelper = new TraversalHelper(graph, ufMock.Object);
196-
var hookExecutor = new ResourceHookExecutor(execHelper, traversalHelper, ufMock.Object, iqMock.Object, graph);
193+
var execHelper = new HookExecutorHelper(gpfMock.Object, options);
194+
var traversalHelper = new TraversalHelper(_graph, ufMock.Object);
195+
var hookExecutor = new ResourceHookExecutor(execHelper, traversalHelper, ufMock.Object, iqMock.Object, inverse);
197196

198197
return (iqMock, ufMock, hookExecutor, mainResource, nestedResource);
199198
}
@@ -215,17 +214,17 @@ public class HooksTestsSetup : HooksDummyData
215214
var secondNestedResource = CreateResourceDefinition(secondNestedDiscovery);
216215

217216
// mocking the GenericProcessorFactory and JsonApiContext and wiring them up.
218-
var (graph, ufMock, iqMock, gpfMock, options) = CreateMocks();
217+
var (inverse, ufMock, iqMock, gpfMock, options) = CreateMocks();
219218

220219
var dbContext = repoDbContextOptions != null ? new AppDbContext(repoDbContextOptions) : null;
221220

222221
SetupProcessorFactoryForResourceDefinition(gpfMock, mainResource.Object, mainDiscovery, dbContext);
223222
SetupProcessorFactoryForResourceDefinition(gpfMock, firstNestedResource.Object, firstNestedDiscovery, dbContext);
224223
SetupProcessorFactoryForResourceDefinition(gpfMock, secondNestedResource.Object, secondNestedDiscovery, dbContext);
225224

226-
var execHelper = new HookExecutorHelper(gpfMock.Object, graph, options);
227-
var traversalHelper = new TraversalHelper(graph, ufMock.Object);
228-
var hookExecutor = new ResourceHookExecutor(execHelper, traversalHelper, ufMock.Object, iqMock.Object, graph);
225+
var execHelper = new HookExecutorHelper(gpfMock.Object, options);
226+
var traversalHelper = new TraversalHelper(_graph, ufMock.Object);
227+
var hookExecutor = new ResourceHookExecutor(execHelper, traversalHelper, ufMock.Object, iqMock.Object, inverse);
229228

230229
return (iqMock, hookExecutor, mainResource, firstNestedResource, secondNestedResource);
231230
}

0 commit comments

Comments
 (0)