1
+ using System ;
2
+ using System . Collections ;
1
3
using System . Collections . Generic ;
2
4
using System . Linq ;
5
+ using System . Reflection ;
3
6
using System . Threading . Tasks ;
4
7
using AutoMapper ;
5
8
using JsonApiDotNetCore . Data ;
10
13
11
14
namespace JsonApiDotNetCore . Services
12
15
{
13
- public class MappingResourceService < TDto , TEntity > :
14
- MappingResourceService < TDto , TEntity , int > ,
15
- IResourceService < TDto >
16
- where TDto : class , IIdentifiable < int >
16
+ public class MappingResourceService < TResource , TEntity >
17
+ : MappingResourceService < TResource , TEntity , int > ,
18
+ IResourceService < TResource >
19
+ where TResource : class , IIdentifiable < int >
17
20
where TEntity : class , IIdentifiable < int >
18
21
{
19
22
public MappingResourceService (
@@ -25,8 +28,9 @@ public MappingResourceService(
25
28
{ }
26
29
}
27
30
28
- public class MappingResourceService < TDto , TEntity , TId > : IResourceService < TDto , TId >
29
- where TDto : class , IIdentifiable < TId >
31
+ public class MappingResourceService < TResource , TEntity , TId >
32
+ : IResourceService < TResource , TId >
33
+ where TResource : class , IIdentifiable < TId >
30
34
where TEntity : class , IIdentifiable < TId >
31
35
{
32
36
private readonly IJsonApiContext _jsonApiContext ;
@@ -42,11 +46,11 @@ public MappingResourceService(
42
46
{
43
47
_jsonApiContext = jsonApiContext ;
44
48
_entities = entityRepository ;
45
- _logger = loggerFactory . CreateLogger < MappingResourceService < TDto , TEntity , TId > > ( ) ;
49
+ _logger = loggerFactory . CreateLogger < MappingResourceService < TResource , TEntity , TId > > ( ) ;
46
50
_mapper = mapper ;
47
51
}
48
52
49
- public virtual async Task < IEnumerable < TDto > > GetAsync ( )
53
+ public virtual async Task < IEnumerable < TResource > > GetAsync ( )
50
54
{
51
55
var entities = _entities . Get ( ) ;
52
56
@@ -63,90 +67,92 @@ public virtual async Task<IEnumerable<TDto>> GetAsync()
63
67
return pagedEntities ;
64
68
}
65
69
66
- public virtual async Task < TDto > GetAsync ( TId id )
70
+ public virtual async Task < TResource > GetAsync ( TId id )
67
71
{
68
- TDto entity ;
72
+ TResource dto ;
69
73
if ( ShouldIncludeRelationships ( ) )
70
- entity = await GetWithRelationshipsAsync ( id ) ;
74
+ dto = await GetWithRelationshipsAsync ( id ) ;
71
75
else
72
- entity = _mapper . Map < TDto > ( await _entities . GetAsync ( id ) ) ;
73
- return entity ;
76
+ {
77
+ TEntity entity = await _entities . GetAsync ( id ) ;
78
+ dto = _mapper . Map < TResource > ( entity ) ;
79
+ }
80
+ return dto ;
74
81
}
75
82
76
83
private bool ShouldIncludeRelationships ( )
77
84
=> ( _jsonApiContext . QuerySet ? . IncludedRelationships != null && _jsonApiContext . QuerySet . IncludedRelationships . Count > 0 ) ;
78
85
79
- private async Task < TDto > GetWithRelationshipsAsync ( TId id )
86
+ private async Task < TResource > GetWithRelationshipsAsync ( TId id )
80
87
{
81
88
var query = _entities . Get ( ) . Where ( e => e . Id . Equals ( id ) ) ;
82
89
_jsonApiContext . QuerySet . IncludedRelationships . ForEach ( r =>
83
90
{
84
91
query = _entities . Include ( query , r ) ;
85
92
} ) ;
86
93
var value = await _entities . FirstOrDefaultAsync ( query ) ;
87
- return _mapper . Map < TDto > ( value ) ;
94
+ return _mapper . Map < TResource > ( value ) ;
88
95
}
89
96
90
97
public virtual async Task < object > GetRelationshipsAsync ( TId id , string relationshipName )
91
98
=> await GetRelationshipAsync ( id , relationshipName ) ;
92
99
93
100
public virtual async Task < object > GetRelationshipAsync ( TId id , string relationshipName )
94
101
{
95
- relationshipName = _jsonApiContext . ContextGraph
96
- . GetRelationshipName < TDto > ( relationshipName ) ;
97
-
98
- if ( relationshipName == null )
99
- throw new JsonApiException ( 422 , "Relationship name not specified." ) ;
100
- if ( _logger . IsEnabled ( LogLevel . Trace ) )
101
- {
102
- _logger . LogTrace ( $ "Looking up '{ relationshipName } '...") ;
103
- }
104
-
105
102
var entity = await _entities . GetAndIncludeAsync ( id , relationshipName ) ;
106
103
// TODO: it would be better if we could distinguish whether or not the relationship was not found,
107
104
// vs the relationship not being set on the instance of T
108
105
if ( entity == null )
106
+ {
109
107
throw new JsonApiException ( 404 , $ "Relationship { relationshipName } not found.") ;
108
+ }
110
109
111
- var relationship = _jsonApiContext . ContextGraph
112
- . GetRelationship ( entity , relationshipName ) ;
113
-
110
+ var resource = _mapper . Map < TResource > ( entity ) ;
111
+ var relationship = _jsonApiContext . ContextGraph . GetRelationship ( resource , relationshipName ) ;
114
112
return relationship ;
115
113
}
116
114
117
- public virtual async Task < TDto > CreateAsync ( TDto entity )
115
+ public virtual async Task < TResource > CreateAsync ( TResource resource )
118
116
{
119
- var createdEntity = await _entities . CreateAsync ( _mapper . Map < TEntity > ( entity ) ) ;
120
- return _mapper . Map < TDto > ( createdEntity ) ;
117
+ var entity = _mapper . Map < TEntity > ( resource ) ;
118
+ entity = await _entities . CreateAsync ( entity ) ;
119
+ return _mapper . Map < TResource > ( entity ) ;
121
120
}
122
121
123
- public virtual async Task < TDto > UpdateAsync ( TId id , TDto entity )
122
+ public virtual async Task < TResource > UpdateAsync ( TId id , TResource resource )
124
123
{
125
- var updatedEntity = await _entities . UpdateAsync ( id , _mapper . Map < TEntity > ( entity ) ) ;
126
- return _mapper . Map < TDto > ( updatedEntity ) ;
124
+ var entity = _mapper . Map < TEntity > ( resource ) ;
125
+ entity = await _entities . UpdateAsync ( id , entity ) ;
126
+ return _mapper . Map < TResource > ( entity ) ;
127
127
}
128
128
129
129
public virtual async Task UpdateRelationshipsAsync ( TId id , string relationshipName , List < DocumentData > relationships )
130
130
{
131
- relationshipName = _jsonApiContext . ContextGraph
132
- . GetRelationshipName < TDto > ( relationshipName ) ;
133
-
134
- if ( relationshipName == null )
135
- throw new JsonApiException ( 422 , "Relationship name not specified." ) ;
136
-
137
131
var entity = await _entities . GetAndIncludeAsync ( id , relationshipName ) ;
138
-
139
132
if ( entity == null )
133
+ {
140
134
throw new JsonApiException ( 404 , $ "Entity with id { id } could not be found.") ;
135
+ }
141
136
142
137
var relationship = _jsonApiContext . ContextGraph
143
- . GetContextEntity ( typeof ( TDto ) )
138
+ . GetContextEntity ( typeof ( TResource ) )
144
139
. Relationships
145
- . FirstOrDefault ( r => r . InternalRelationshipName == relationshipName ) ;
140
+ . FirstOrDefault ( r => r . PublicRelationshipName == relationshipName ) ;
141
+ var relationshipType = relationship . Type ;
142
+
143
+ // update relationship type with internalname
144
+ var entityProperty = typeof ( TEntity ) . GetProperty ( relationship . InternalRelationshipName ) ;
145
+ if ( entityProperty == null )
146
+ {
147
+ throw new JsonApiException ( 404 , $ "Property { relationship . InternalRelationshipName } could not be found on entity.") ;
148
+ }
149
+ relationship . Type = relationship . IsHasMany ? entityProperty . PropertyType . GetGenericArguments ( ) [ 0 ] : entityProperty . PropertyType ;
146
150
147
151
var relationshipIds = relationships . Select ( r => r ? . Id ? . ToString ( ) ) ;
148
152
149
153
await _entities . UpdateRelationshipsAsync ( entity , relationship , relationshipIds ) ;
154
+
155
+ relationship . Type = relationshipType ;
150
156
}
151
157
152
158
public virtual async Task < bool > DeleteAsync ( TId id )
@@ -171,18 +177,18 @@ protected virtual IQueryable<TEntity> ApplySortAndFilterQuery(IQueryable<TEntity
171
177
return entities ;
172
178
}
173
179
174
- protected virtual async Task < IEnumerable < TDto > > ApplyPageQueryAsync ( IQueryable < TEntity > entities )
180
+ protected virtual async Task < IEnumerable < TResource > > ApplyPageQueryAsync ( IQueryable < TEntity > entities )
175
181
{
176
182
var pageManager = _jsonApiContext . PageManager ;
177
183
if ( ! pageManager . IsPaginated )
178
- return _mapper . Map < IEnumerable < TDto > > ( await _entities . ToListAsync ( entities ) ) ;
184
+ return _mapper . Map < IEnumerable < TResource > > ( await _entities . ToListAsync ( entities ) ) ;
179
185
180
186
if ( _logger ? . IsEnabled ( LogLevel . Information ) == true )
181
187
{
182
188
_logger ? . LogInformation ( $ "Applying paging query. Fetching page { pageManager . CurrentPage } with { pageManager . PageSize } entities") ;
183
189
}
184
190
185
- return _mapper . Map < IEnumerable < TDto > > ( await _entities . PageAsync ( entities , pageManager . PageSize , pageManager . CurrentPage ) ) ;
191
+ return _mapper . Map < IEnumerable < TResource > > ( await _entities . PageAsync ( entities , pageManager . PageSize , pageManager . CurrentPage ) ) ;
186
192
}
187
193
188
194
protected virtual IQueryable < TEntity > IncludeRelationships ( IQueryable < TEntity > entities , List < string > relationships )
0 commit comments