Skip to content

Commit f438d5c

Browse files
committed
combined entityresourceservice and mapperresourceservice into defaultresourceservice
1 parent 7c104c2 commit f438d5c

File tree

7 files changed

+132
-261
lines changed

7 files changed

+132
-261
lines changed

src/Examples/ResourceEntitySeparationExample/Controllers/CoursesController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public class CoursesController : JsonApiController<CourseResource>
99
{
1010
public CoursesController(
1111
IJsonApiContext jsonApiContext,
12-
IResourceService<CourseResource> resourceService,
12+
IResourceService<CourseResource, int> resourceService,
1313
ILoggerFactory loggerFactory)
1414
: base(jsonApiContext, resourceService, loggerFactory)
1515
{ }

src/Examples/ResourceEntitySeparationExample/Controllers/DepartmentsController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class DepartmentsController : JsonApiController<DepartmentResource>
1010
{
1111
public DepartmentsController(
1212
IJsonApiContext jsonApiContext,
13-
IResourceService<DepartmentResource> resourceService,
13+
IResourceService<DepartmentResource, int> resourceService,
1414
ILoggerFactory loggerFactory)
1515
: base(jsonApiContext, resourceService, loggerFactory)
1616
{ }

src/Examples/ResourceEntitySeparationExample/Controllers/StudentsController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public class StudentsController : JsonApiController<StudentResource>
99
{
1010
public StudentsController(
1111
IJsonApiContext jsonApiContext,
12-
IResourceService<StudentResource> resourceService,
12+
IResourceService<StudentResource, int> resourceService,
1313
ILoggerFactory loggerFactory)
1414
: base(jsonApiContext, resourceService, loggerFactory)
1515
{ }

src/Examples/ResourceEntitySeparationExample/Startup.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ public virtual IServiceProvider ConfigureServices(IServiceCollection services)
5757

5858
// inject automapper and mapping resources
5959
services.AddAutoMapper();
60-
services.AddScoped<IResourceService<CourseResource>, MappingResourceService<CourseResource, CourseEntity>>();
61-
services.AddScoped<IResourceService<DepartmentResource>, MappingResourceService<DepartmentResource, DepartmentEntity>>();
62-
services.AddScoped<IResourceService<StudentResource>, MappingResourceService<StudentResource, StudentEntity>>();
60+
services.AddScoped<IResourceService<CourseResource, int>, DefaultResourceService<CourseResource, CourseEntity, int>>();
61+
services.AddScoped<IResourceService<DepartmentResource, int>, DefaultResourceService<DepartmentResource, DepartmentEntity, int>>();
62+
services.AddScoped<IResourceService<StudentResource, int>, DefaultResourceService<StudentResource, StudentEntity, int>>();
6363

6464
var provider = services.BuildServiceProvider();
6565
var appContext = provider.GetRequiredService<AppDbContext>();

src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public static void AddJsonApiInternals(
9393
if (jsonApiOptions.ContextGraph.UsesDbContext == false)
9494
{
9595
services.AddScoped<DbContext>();
96-
services.AddSingleton<DbContextOptions>(new DbContextOptionsBuilder().Options);
96+
services.AddSingleton(new DbContextOptionsBuilder().Options);
9797
}
9898

9999
if (jsonApiOptions.EnableOperations)
@@ -102,29 +102,29 @@ public static void AddJsonApiInternals(
102102
services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>));
103103
services.AddScoped(typeof(IEntityRepository<,>), typeof(DefaultEntityRepository<,>));
104104

105-
services.AddScoped(typeof(ICreateService<>), typeof(EntityResourceService<>));
106-
services.AddScoped(typeof(ICreateService<,>), typeof(EntityResourceService<,>));
105+
services.AddScoped(typeof(ICreateService<>), typeof(DefaultResourceService<>));
106+
services.AddScoped(typeof(ICreateService<,>), typeof(DefaultResourceService<,>));
107107

108-
services.AddScoped(typeof(IGetAllService<>), typeof(EntityResourceService<>));
109-
services.AddScoped(typeof(IGetAllService<,>), typeof(EntityResourceService<,>));
108+
services.AddScoped(typeof(IGetAllService<>), typeof(DefaultResourceService<>));
109+
services.AddScoped(typeof(IGetAllService<,>), typeof(DefaultResourceService<,>));
110110

111-
services.AddScoped(typeof(IGetByIdService<>), typeof(EntityResourceService<>));
112-
services.AddScoped(typeof(IGetByIdService<,>), typeof(EntityResourceService<,>));
111+
services.AddScoped(typeof(IGetByIdService<>), typeof(DefaultResourceService<>));
112+
services.AddScoped(typeof(IGetByIdService<,>), typeof(DefaultResourceService<,>));
113113

114-
services.AddScoped(typeof(IGetRelationshipService<,>), typeof(EntityResourceService<>));
115-
services.AddScoped(typeof(IGetRelationshipService<,>), typeof(EntityResourceService<,>));
114+
services.AddScoped(typeof(IGetRelationshipService<,>), typeof(DefaultResourceService<>));
115+
services.AddScoped(typeof(IGetRelationshipService<,>), typeof(DefaultResourceService<,>));
116116

117-
services.AddScoped(typeof(IUpdateService<>), typeof(EntityResourceService<>));
118-
services.AddScoped(typeof(IUpdateService<,>), typeof(EntityResourceService<,>));
117+
services.AddScoped(typeof(IUpdateService<>), typeof(DefaultResourceService<>));
118+
services.AddScoped(typeof(IUpdateService<,>), typeof(DefaultResourceService<,>));
119119

120-
services.AddScoped(typeof(IDeleteService<>), typeof(EntityResourceService<>));
121-
services.AddScoped(typeof(IDeleteService<,>), typeof(EntityResourceService<,>));
120+
services.AddScoped(typeof(IDeleteService<>), typeof(DefaultResourceService<>));
121+
services.AddScoped(typeof(IDeleteService<,>), typeof(DefaultResourceService<,>));
122122

123-
services.AddScoped(typeof(IResourceService<>), typeof(EntityResourceService<>));
124-
services.AddScoped(typeof(IResourceService<,>), typeof(EntityResourceService<,>));
123+
services.AddScoped(typeof(IResourceService<>), typeof(DefaultResourceService<>));
124+
services.AddScoped(typeof(IResourceService<,>), typeof(DefaultResourceService<,>));
125125

126-
services.AddSingleton<JsonApiOptions>(jsonApiOptions);
127-
services.AddSingleton<IContextGraph>(jsonApiOptions.ContextGraph);
126+
services.AddSingleton(jsonApiOptions);
127+
services.AddSingleton(jsonApiOptions.ContextGraph);
128128
services.AddScoped<IJsonApiContext, JsonApiContext>();
129129
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
130130
services.AddScoped<IScopedServiceProvider, RequestScopedServiceProvider>();
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,41 @@
1-
using System;
2-
using System.Collections;
3-
using System.Collections.Generic;
4-
using System.Linq;
5-
using System.Reflection;
6-
using System.Threading.Tasks;
71
using AutoMapper;
82
using JsonApiDotNetCore.Data;
9-
using JsonApiDotNetCore.Extensions;
103
using JsonApiDotNetCore.Internal;
114
using JsonApiDotNetCore.Models;
125
using Microsoft.Extensions.Logging;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Threading.Tasks;
1310

1411
namespace JsonApiDotNetCore.Services
1512
{
16-
public class MappingResourceService<TResource, TEntity>
17-
: MappingResourceService<TResource, TEntity, int>,
13+
public class DefaultResourceService<TResource> : DefaultResourceService<TResource, int>,
1814
IResourceService<TResource>
1915
where TResource : class, IIdentifiable<int>
20-
where TEntity : class, IIdentifiable<int>
2116
{
22-
public MappingResourceService(
23-
IJsonApiContext jsonApiContext,
24-
IEntityRepository<TEntity> entityRepository,
25-
ILoggerFactory loggerFactory,
26-
IMapper mapper)
27-
: base(jsonApiContext, entityRepository, loggerFactory, mapper)
17+
public DefaultResourceService(
18+
IJsonApiContext jsonApiContext,
19+
IEntityRepository<TResource> entityRepository,
20+
ILoggerFactory loggerFactory) :
21+
base(jsonApiContext, entityRepository, loggerFactory)
22+
{ }
23+
}
24+
25+
public class DefaultResourceService<TResource, TId> : DefaultResourceService<TResource, TResource, TId>,
26+
IResourceService<TResource, TId>
27+
where TResource : class, IIdentifiable<TId>
28+
{
29+
public DefaultResourceService(
30+
IJsonApiContext jsonApiContext,
31+
IEntityRepository<TResource, TId> entityRepository,
32+
ILoggerFactory loggerFactory) :
33+
base(jsonApiContext, entityRepository, loggerFactory)
2834
{ }
2935
}
3036

31-
public class MappingResourceService<TResource, TEntity, TId>
32-
: IResourceService<TResource, TId>
37+
public class DefaultResourceService<TResource, TEntity, TId> :
38+
IResourceService<TResource, TId>
3339
where TResource : class, IIdentifiable<TId>
3440
where TEntity : class, IIdentifiable<TId>
3541
{
@@ -38,18 +44,49 @@ public class MappingResourceService<TResource, TEntity, TId>
3844
private readonly ILogger _logger;
3945
private readonly IMapper _mapper;
4046

41-
public MappingResourceService(
47+
public DefaultResourceService(
48+
IJsonApiContext jsonApiContext,
49+
IEntityRepository<TEntity, TId> entityRepository,
50+
ILoggerFactory loggerFactory)
51+
{
52+
// no mapper provided, TResource & TEntity must be the same type
53+
if (typeof(TResource) != typeof(TEntity))
54+
{
55+
throw new InvalidOperationException("Resource and Entity types are NOT the same. " +
56+
"Please provide a mapper.");
57+
}
58+
59+
_jsonApiContext = jsonApiContext;
60+
_entities = entityRepository;
61+
_logger = loggerFactory.CreateLogger<DefaultResourceService<TResource, TEntity, TId>>();
62+
}
63+
64+
public DefaultResourceService(
4265
IJsonApiContext jsonApiContext,
4366
IEntityRepository<TEntity, TId> entityRepository,
4467
ILoggerFactory loggerFactory,
4568
IMapper mapper)
4669
{
4770
_jsonApiContext = jsonApiContext;
4871
_entities = entityRepository;
49-
_logger = loggerFactory.CreateLogger<MappingResourceService<TResource, TEntity, TId>>();
72+
_logger = loggerFactory.CreateLogger<DefaultResourceService<TResource, TEntity, TId>>();
5073
_mapper = mapper;
5174
}
5275

76+
public virtual async Task<TResource> CreateAsync(TResource resource)
77+
{
78+
var entity = (typeof(TResource) == typeof(TEntity)) ? resource as TEntity :
79+
_mapper.Map<TEntity>(resource);
80+
entity = await _entities.CreateAsync(entity);
81+
return (typeof(TResource) == typeof(TEntity)) ? entity as TResource :
82+
_mapper.Map<TResource>(entity);
83+
}
84+
85+
public virtual async Task<bool> DeleteAsync(TId id)
86+
{
87+
return await _entities.DeleteAsync(id);
88+
}
89+
5390
public virtual async Task<IEnumerable<TResource>> GetAsync()
5491
{
5592
var entities = _entities.Get();
@@ -75,25 +112,12 @@ public virtual async Task<TResource> GetAsync(TId id)
75112
else
76113
{
77114
TEntity entity = await _entities.GetAsync(id);
78-
dto = _mapper.Map<TResource>(entity);
115+
dto = (typeof(TResource) == typeof(TEntity)) ? entity as TResource :
116+
_mapper.Map<TResource>(entity);
79117
}
80118
return dto;
81119
}
82120

83-
private bool ShouldIncludeRelationships()
84-
=> (_jsonApiContext.QuerySet?.IncludedRelationships != null && _jsonApiContext.QuerySet.IncludedRelationships.Count > 0);
85-
86-
private async Task<TResource> GetWithRelationshipsAsync(TId id)
87-
{
88-
var query = _entities.Get().Where(e => e.Id.Equals(id));
89-
_jsonApiContext.QuerySet.IncludedRelationships.ForEach(r =>
90-
{
91-
query = _entities.Include(query, r);
92-
});
93-
var value = await _entities.FirstOrDefaultAsync(query);
94-
return _mapper.Map<TResource>(value);
95-
}
96-
97121
public virtual async Task<object> GetRelationshipsAsync(TId id, string relationshipName)
98122
=> await GetRelationshipAsync(id, relationshipName);
99123

@@ -107,26 +131,23 @@ public virtual async Task<object> GetRelationshipAsync(TId id, string relationsh
107131
throw new JsonApiException(404, $"Relationship {relationshipName} not found.");
108132
}
109133

110-
var resource = _mapper.Map<TResource>(entity);
134+
var resource = (typeof(TResource) == typeof(TEntity)) ? entity as TResource :
135+
_mapper.Map<TResource>(entity);
111136
var relationship = _jsonApiContext.ContextGraph.GetRelationship(resource, relationshipName);
112137
return relationship;
113138
}
114139

115-
public virtual async Task<TResource> CreateAsync(TResource resource)
116-
{
117-
var entity = _mapper.Map<TEntity>(resource);
118-
entity = await _entities.CreateAsync(entity);
119-
return _mapper.Map<TResource>(entity);
120-
}
121-
122140
public virtual async Task<TResource> UpdateAsync(TId id, TResource resource)
123141
{
124-
var entity = _mapper.Map<TEntity>(resource);
142+
var entity = (typeof(TResource) == typeof(TEntity)) ? resource as TEntity :
143+
_mapper.Map<TEntity>(resource);
125144
entity = await _entities.UpdateAsync(id, entity);
126-
return _mapper.Map<TResource>(entity);
145+
return (typeof(TResource) == typeof(TEntity)) ? entity as TResource :
146+
_mapper.Map<TResource>(entity);
127147
}
128148

129-
public virtual async Task UpdateRelationshipsAsync(TId id, string relationshipName, List<DocumentData> relationships)
149+
public virtual async Task UpdateRelationshipsAsync(TId id, string relationshipName,
150+
List<DocumentData> relationships)
130151
{
131152
var entity = await _entities.GetAndIncludeAsync(id, relationshipName);
132153
if (entity == null)
@@ -137,16 +158,18 @@ public virtual async Task UpdateRelationshipsAsync(TId id, string relationshipNa
137158
var relationship = _jsonApiContext.ContextGraph
138159
.GetContextEntity(typeof(TResource))
139160
.Relationships
140-
.FirstOrDefault(r => r.PublicRelationshipName == relationshipName);
161+
.FirstOrDefault(r => r.Is(relationshipName));
141162
var relationshipType = relationship.Type;
142163

143164
// update relationship type with internalname
144165
var entityProperty = typeof(TEntity).GetProperty(relationship.InternalRelationshipName);
145166
if (entityProperty == null)
146167
{
147-
throw new JsonApiException(404, $"Property {relationship.InternalRelationshipName} could not be found on entity.");
168+
throw new JsonApiException(404, $"Property {relationship.InternalRelationshipName} " +
169+
$"could not be found on entity.");
148170
}
149-
relationship.Type = relationship.IsHasMany ? entityProperty.PropertyType.GetGenericArguments()[0] : entityProperty.PropertyType;
171+
relationship.Type = relationship.IsHasMany ? entityProperty.PropertyType.GetGenericArguments()[0] :
172+
entityProperty.PropertyType;
150173

151174
var relationshipIds = relationships.Select(r => r?.Id?.ToString());
152175

@@ -155,9 +178,26 @@ public virtual async Task UpdateRelationshipsAsync(TId id, string relationshipNa
155178
relationship.Type = relationshipType;
156179
}
157180

158-
public virtual async Task<bool> DeleteAsync(TId id)
181+
protected virtual async Task<IEnumerable<TResource>> ApplyPageQueryAsync(IQueryable<TEntity> entities)
159182
{
160-
return await _entities.DeleteAsync(id);
183+
var pageManager = _jsonApiContext.PageManager;
184+
if (!pageManager.IsPaginated)
185+
{
186+
var allEntities = await _entities.ToListAsync(entities);
187+
return (typeof(TResource) == typeof(TEntity)) ? allEntities as IEnumerable<TResource> :
188+
_mapper.Map<IEnumerable<TResource>>(allEntities);
189+
}
190+
191+
if (_logger?.IsEnabled(LogLevel.Information) == true)
192+
{
193+
_logger?.LogInformation($"Applying paging query. Fetching page {pageManager.CurrentPage} " +
194+
$"with {pageManager.PageSize} entities");
195+
}
196+
197+
var pagedEntities = await _entities.PageAsync(entities, pageManager.PageSize,
198+
pageManager.CurrentPage);
199+
return (typeof(TResource) == typeof(TEntity)) ? pagedEntities as IEnumerable<TResource> :
200+
_mapper.Map<IEnumerable<TResource>>(pagedEntities);
161201
}
162202

163203
protected virtual IQueryable<TEntity> ApplySortAndFilterQuery(IQueryable<TEntity> entities)
@@ -177,21 +217,8 @@ protected virtual IQueryable<TEntity> ApplySortAndFilterQuery(IQueryable<TEntity
177217
return entities;
178218
}
179219

180-
protected virtual async Task<IEnumerable<TResource>> ApplyPageQueryAsync(IQueryable<TEntity> entities)
181-
{
182-
var pageManager = _jsonApiContext.PageManager;
183-
if (!pageManager.IsPaginated)
184-
return _mapper.Map<IEnumerable<TResource>>(await _entities.ToListAsync(entities));
185-
186-
if (_logger?.IsEnabled(LogLevel.Information) == true)
187-
{
188-
_logger?.LogInformation($"Applying paging query. Fetching page {pageManager.CurrentPage} with {pageManager.PageSize} entities");
189-
}
190-
191-
return _mapper.Map<IEnumerable<TResource>>(await _entities.PageAsync(entities, pageManager.PageSize, pageManager.CurrentPage));
192-
}
193-
194-
protected virtual IQueryable<TEntity> IncludeRelationships(IQueryable<TEntity> entities, List<string> relationships)
220+
protected virtual IQueryable<TEntity> IncludeRelationships(IQueryable<TEntity> entities,
221+
List<string> relationships)
195222
{
196223
_jsonApiContext.IncludedRelationships = relationships;
197224

@@ -200,5 +227,21 @@ protected virtual IQueryable<TEntity> IncludeRelationships(IQueryable<TEntity> e
200227

201228
return entities;
202229
}
230+
231+
private async Task<TResource> GetWithRelationshipsAsync(TId id)
232+
{
233+
var query = _entities.Get().Where(e => e.Id.Equals(id));
234+
_jsonApiContext.QuerySet.IncludedRelationships.ForEach(r =>
235+
{
236+
query = _entities.Include(query, r);
237+
});
238+
var value = await _entities.FirstOrDefaultAsync(query);
239+
return (typeof(TResource) == typeof(TEntity)) ? value as TResource :
240+
_mapper.Map<TResource>(value);
241+
}
242+
243+
private bool ShouldIncludeRelationships()
244+
=> (_jsonApiContext.QuerySet?.IncludedRelationships != null &&
245+
_jsonApiContext.QuerySet.IncludedRelationships.Count > 0);
203246
}
204247
}

0 commit comments

Comments
 (0)