10
10
using JsonApiDotNetCore . Internal . Contracts ;
11
11
using JsonApiDotNetCore . Models ;
12
12
using JsonApiDotNetCore . Models . Links ;
13
- using Microsoft . EntityFrameworkCore ;
14
13
using Microsoft . Extensions . Logging ;
15
14
16
15
namespace JsonApiDotNetCore . Builders
17
16
{
18
17
public class ResourceGraphBuilder : IResourceGraphBuilder
19
18
{
20
- private readonly List < ResourceContext > _entities = new List < ResourceContext > ( ) ;
21
- private readonly List < ValidationResult > _validationResults = new List < ValidationResult > ( ) ;
22
- private readonly IResourceNameFormatter _resourceNameFormatter = new KebabCaseFormatter ( ) ;
19
+ private List < ResourceContext > _resources { get ; set ; } = new List < ResourceContext > ( ) ;
20
+ private List < ValidationResult > _validationResults { get ; set ; } = new List < ValidationResult > ( ) ;
21
+ private IResourceNameFormatter _formatter { get ; set ; } = new KebabCaseFormatter ( ) ;
23
22
24
23
public ResourceGraphBuilder ( ) { }
25
24
26
25
public ResourceGraphBuilder ( IResourceNameFormatter formatter )
27
26
{
28
- _resourceNameFormatter = formatter ;
27
+ _formatter = formatter ;
29
28
}
30
29
31
30
/// <inheritdoc />
32
31
public IResourceGraph Build ( )
33
32
{
34
- _entities . ForEach ( SetResourceLinksOptions ) ;
35
- var resourceGraph = new ResourceGraph ( _entities , _validationResults ) ;
33
+ _resources . ForEach ( SetResourceLinksOptions ) ;
34
+ var resourceGraph = new ResourceGraph ( _resources , _validationResults ) ;
36
35
return resourceGraph ;
37
36
}
38
37
@@ -56,13 +55,19 @@ public IResourceGraphBuilder AddResource<TResource, TId>(string pluralizedTypeNa
56
55
=> AddResource ( typeof ( TResource ) , typeof ( TId ) , pluralizedTypeName ) ;
57
56
58
57
/// <inheritdoc />
59
- public IResourceGraphBuilder AddResource ( Type entityType , Type idType , string pluralizedTypeName = null )
58
+ public IResourceGraphBuilder AddResource ( Type resourceType , Type idType = null , string pluralizedTypeName = null )
60
59
{
61
- AssertEntityIsNotAlreadyDefined ( entityType ) ;
62
-
63
- pluralizedTypeName = pluralizedTypeName ?? _resourceNameFormatter . FormatResourceName ( entityType ) ;
64
-
65
- _entities . Add ( GetEntity ( pluralizedTypeName , entityType , idType ) ) ;
60
+ AssertEntityIsNotAlreadyDefined ( resourceType ) ;
61
+ if ( resourceType . Implements < IIdentifiable > ( ) )
62
+ {
63
+ pluralizedTypeName ??= _formatter . FormatResourceName ( resourceType ) ;
64
+ idType ??= TypeLocator . GetIdType ( resourceType ) ;
65
+ _resources . Add ( GetEntity ( pluralizedTypeName , resourceType , idType ) ) ;
66
+ }
67
+ else
68
+ {
69
+ _validationResults . Add ( new ValidationResult ( LogLevel . Warning , $ "{ resourceType } does not implement 'IIdentifiable<>'. ") ) ;
70
+ }
66
71
67
72
return this ;
68
73
}
@@ -93,7 +98,7 @@ protected virtual List<AttrAttribute> GetAttributes(Type entityType)
93
98
{
94
99
var idAttr = new AttrAttribute ( )
95
100
{
96
- PublicAttributeName = _resourceNameFormatter . FormatPropertyName ( prop ) ,
101
+ PublicAttributeName = _formatter . FormatPropertyName ( prop ) ,
97
102
PropertyInfo = prop ,
98
103
InternalAttributeName = prop . Name
99
104
} ;
@@ -105,7 +110,7 @@ protected virtual List<AttrAttribute> GetAttributes(Type entityType)
105
110
if ( attribute == null )
106
111
continue ;
107
112
108
- attribute . PublicAttributeName = attribute . PublicAttributeName ?? _resourceNameFormatter . FormatPropertyName ( prop ) ;
113
+ attribute . PublicAttributeName = attribute . PublicAttributeName ?? _formatter . FormatPropertyName ( prop ) ;
109
114
attribute . InternalAttributeName = prop . Name ;
110
115
attribute . PropertyInfo = prop ;
111
116
@@ -123,7 +128,7 @@ protected virtual List<RelationshipAttribute> GetRelationships(Type entityType)
123
128
var attribute = ( RelationshipAttribute ) prop . GetCustomAttribute ( typeof ( RelationshipAttribute ) ) ;
124
129
if ( attribute == null ) continue ;
125
130
126
- attribute . PublicRelationshipName = attribute . PublicRelationshipName ?? _resourceNameFormatter . FormatPropertyName ( prop ) ;
131
+ attribute . PublicRelationshipName = attribute . PublicRelationshipName ?? _formatter . FormatPropertyName ( prop ) ;
127
132
attribute . InternalRelationshipName = prop . Name ;
128
133
attribute . RightType = GetRelationshipType ( attribute , prop ) ;
129
134
attribute . LeftType = entityType ;
@@ -178,63 +183,9 @@ protected virtual Type GetRelationshipType(RelationshipAttribute relation, Prope
178
183
179
184
private Type GetResourceDefinitionType ( Type entityType ) => typeof ( ResourceDefinition < > ) . MakeGenericType ( entityType ) ;
180
185
181
- /// <inheritdoc />
182
- public IResourceGraphBuilder AddDbContext < T > ( ) where T : DbContext
183
- {
184
- var contextType = typeof ( T ) ;
185
- var contextProperties = contextType . GetProperties ( ) ;
186
- foreach ( var property in contextProperties )
187
- {
188
- var dbSetType = property . PropertyType ;
189
- if ( dbSetType . GetTypeInfo ( ) . IsGenericType
190
- && dbSetType . GetGenericTypeDefinition ( ) == typeof ( DbSet < > ) )
191
- {
192
- var entityType = dbSetType . GetGenericArguments ( ) [ 0 ] ;
193
- AssertEntityIsNotAlreadyDefined ( entityType ) ;
194
- var ( isJsonApiResource , idType ) = GetIdType ( entityType ) ;
195
- if ( isJsonApiResource )
196
- _entities . Add ( GetEntity ( GetResourceNameFromDbSetProperty ( property , entityType ) , entityType , idType ) ) ;
197
- }
198
- }
199
-
200
- return this ;
201
- }
202
-
203
- private string GetResourceNameFromDbSetProperty ( PropertyInfo property , Type resourceType )
204
- {
205
- // this check is actually duplicated in the DefaultResourceNameFormatter
206
- // however, we perform it here so that we allow class attributes to be prioritized over
207
- // the DbSet attribute. Eventually, the DbSet attribute should be deprecated.
208
- //
209
- // check the class definition first
210
- // [Resource("models"] public class Model : Identifiable { /* ... */ }
211
- if ( resourceType . GetCustomAttribute ( typeof ( ResourceAttribute ) ) is ResourceAttribute classResourceAttribute )
212
- return classResourceAttribute . ResourceName ;
213
-
214
- // check the DbContext member next
215
- // [Resource("models")] public DbSet<Model> Models { get; set; }
216
- if ( property . GetCustomAttribute ( typeof ( ResourceAttribute ) ) is ResourceAttribute resourceAttribute )
217
- return resourceAttribute . ResourceName ;
218
-
219
- // fallback to the established convention using the DbSet Property.Name
220
- // e.g DbSet<FooBar> FooBars { get; set; } => "foo-bars"
221
- return _resourceNameFormatter . FormatResourceName ( resourceType ) ;
222
- }
223
-
224
- private ( bool isJsonApiResource , Type idType ) GetIdType ( Type resourceType )
225
- {
226
- var possible = TypeLocator . GetIdType ( resourceType ) ;
227
- if ( possible . isJsonApiResource )
228
- return possible ;
229
-
230
- _validationResults . Add ( new ValidationResult ( LogLevel . Warning , $ "{ resourceType } does not implement 'IIdentifiable<>'. ") ) ;
231
-
232
- return ( false , null ) ;
233
- }
234
-
235
186
private void AssertEntityIsNotAlreadyDefined ( Type entityType )
236
187
{
237
- if ( _entities . Any ( e => e . ResourceType == entityType ) )
188
+ if ( _resources . Any ( e => e . ResourceType == entityType ) )
238
189
throw new InvalidOperationException ( $ "Cannot add entity type { entityType } to context resourceGraph, there is already an entity of that type configured.") ;
239
190
}
240
191
}
0 commit comments