13
13
14
14
namespace JsonApiDotNetCore . Data
15
15
{
16
+ /// <inheritdoc />
16
17
public class DefaultEntityRepository < TEntity >
17
18
: DefaultEntityRepository < TEntity , int > ,
18
19
IEntityRepository < TEntity >
@@ -26,8 +27,13 @@ public DefaultEntityRepository(
26
27
{ }
27
28
}
28
29
30
+ /// <summary>
31
+ /// Provides a default repository implementation and is responsible for
32
+ /// abstracting any EF Core APIs away from the service layer.
33
+ /// </summary>
29
34
public class DefaultEntityRepository < TEntity , TId >
30
- : IEntityRepository < TEntity , TId >
35
+ : IEntityRepository < TEntity , TId > ,
36
+ IEntityFrameworkRepository < TEntity >
31
37
where TEntity : class , IIdentifiable < TId >
32
38
{
33
39
private readonly DbContext _context ;
@@ -48,7 +54,7 @@ public DefaultEntityRepository(
48
54
_genericProcessorFactory = _jsonApiContext . GenericProcessorFactory ;
49
55
}
50
56
51
- /// </ inheritdoc>
57
+ /// <inheritdoc / >
52
58
public virtual IQueryable < TEntity > Get ( )
53
59
{
54
60
if ( _jsonApiContext . QuerySet ? . Fields != null && _jsonApiContext . QuerySet . Fields . Count > 0 )
@@ -57,41 +63,43 @@ public virtual IQueryable<TEntity> Get()
57
63
return _dbSet ;
58
64
}
59
65
60
- /// </ inheritdoc>
66
+ /// <inheritdoc / >
61
67
public virtual IQueryable < TEntity > Filter ( IQueryable < TEntity > entities , FilterQuery filterQuery )
62
68
{
63
69
return entities . Filter ( _jsonApiContext , filterQuery ) ;
64
70
}
65
71
66
- /// </ inheritdoc>
72
+ /// <inheritdoc / >
67
73
public virtual IQueryable < TEntity > Sort ( IQueryable < TEntity > entities , List < SortQuery > sortQueries )
68
74
{
69
75
return entities . Sort ( sortQueries ) ;
70
76
}
71
77
72
- /// </ inheritdoc>
78
+ /// <inheritdoc / >
73
79
public virtual async Task < TEntity > GetAsync ( TId id )
74
80
{
75
81
return await Get ( ) . SingleOrDefaultAsync ( e => e . Id . Equals ( id ) ) ;
76
82
}
77
83
78
- /// </ inheritdoc>
84
+ /// <inheritdoc / >
79
85
public virtual async Task < TEntity > GetAndIncludeAsync ( TId id , string relationshipName )
80
86
{
81
87
_logger . LogDebug ( $ "[JADN] GetAndIncludeAsync({ id } , { relationshipName } )") ;
82
88
83
- var result = await Include ( Get ( ) , relationshipName ) . SingleOrDefaultAsync ( e => e . Id . Equals ( id ) ) ;
89
+ var includedSet = Include ( Get ( ) , relationshipName ) ;
90
+ var result = await includedSet . SingleOrDefaultAsync ( e => e . Id . Equals ( id ) ) ;
84
91
85
92
return result ;
86
93
}
87
94
88
- /// </ inheritdoc>
95
+ /// <inheritdoc / >
89
96
public virtual async Task < TEntity > CreateAsync ( TEntity entity )
90
97
{
91
98
AttachRelationships ( ) ;
92
99
_dbSet . Add ( entity ) ;
93
100
94
101
await _context . SaveChangesAsync ( ) ;
102
+
95
103
return entity ;
96
104
}
97
105
@@ -101,6 +109,28 @@ protected virtual void AttachRelationships()
101
109
AttachHasOnePointers ( ) ;
102
110
}
103
111
112
+ /// <inheritdoc />
113
+ public void DetachRelationshipPointers ( TEntity entity )
114
+ {
115
+ foreach ( var hasOneRelationship in _jsonApiContext . HasOneRelationshipPointers . Get ( ) )
116
+ {
117
+ _context . Entry ( hasOneRelationship . Value ) . State = EntityState . Detached ;
118
+ }
119
+
120
+ foreach ( var hasManyRelationship in _jsonApiContext . HasManyRelationshipPointers . Get ( ) )
121
+ {
122
+ foreach ( var pointer in hasManyRelationship . Value )
123
+ {
124
+ _context . Entry ( pointer ) . State = EntityState . Detached ;
125
+ }
126
+
127
+ // HACK: detaching has many relationships doesn't appear to be sufficient
128
+ // the navigation property actually needs to be nulled out, otherwise
129
+ // EF adds duplicate instances to the collection
130
+ hasManyRelationship . Key . SetValue ( entity , null ) ;
131
+ }
132
+ }
133
+
104
134
/// <summary>
105
135
/// This is used to allow creation of HasMany relationships when the
106
136
/// dependent side of the relationship already exists.
@@ -129,7 +159,7 @@ private void AttachHasOnePointers()
129
159
_context . Entry ( relationship . Value ) . State = EntityState . Unchanged ;
130
160
}
131
161
132
- /// </ inheritdoc>
162
+ /// <inheritdoc / >
133
163
public virtual async Task < TEntity > UpdateAsync ( TId id , TEntity entity )
134
164
{
135
165
var oldEntity = await GetAsync ( id ) ;
@@ -148,14 +178,14 @@ public virtual async Task<TEntity> UpdateAsync(TId id, TEntity entity)
148
178
return oldEntity ;
149
179
}
150
180
151
- /// </ inheritdoc>
181
+ /// <inheritdoc / >
152
182
public async Task UpdateRelationshipsAsync ( object parent , RelationshipAttribute relationship , IEnumerable < string > relationshipIds )
153
183
{
154
184
var genericProcessor = _genericProcessorFactory . GetProcessor < IGenericProcessor > ( typeof ( GenericProcessor < > ) , relationship . Type ) ;
155
185
await genericProcessor . UpdateRelationshipsAsync ( parent , relationship , relationshipIds ) ;
156
186
}
157
187
158
- /// </ inheritdoc>
188
+ /// <inheritdoc / >
159
189
public virtual async Task < bool > DeleteAsync ( TId id )
160
190
{
161
191
var entity = await GetAsync ( id ) ;
@@ -170,7 +200,7 @@ public virtual async Task<bool> DeleteAsync(TId id)
170
200
return true ;
171
201
}
172
202
173
- /// </ inheritdoc>
203
+ /// <inheritdoc / >
174
204
public virtual IQueryable < TEntity > Include ( IQueryable < TEntity > entities , string relationshipName )
175
205
{
176
206
var entity = _jsonApiContext . RequestEntity ;
@@ -185,10 +215,11 @@ public virtual IQueryable<TEntity> Include(IQueryable<TEntity> entities, string
185
215
{
186
216
throw new JsonApiException ( 400 , $ "Including the relationship { relationshipName } on { entity . EntityName } is not allowed") ;
187
217
}
218
+
188
219
return entities . Include ( relationship . InternalRelationshipName ) ;
189
220
}
190
221
191
- /// </ inheritdoc>
222
+ /// <inheritdoc / >
192
223
public virtual async Task < IEnumerable < TEntity > > PageAsync ( IQueryable < TEntity > entities , int pageSize , int pageNumber )
193
224
{
194
225
if ( pageNumber >= 0 )
@@ -209,23 +240,23 @@ public virtual async Task<IEnumerable<TEntity>> PageAsync(IQueryable<TEntity> en
209
240
. ToListAsync ( ) ;
210
241
}
211
242
212
- /// </ inheritdoc>
243
+ /// <inheritdoc / >
213
244
public async Task < int > CountAsync ( IQueryable < TEntity > entities )
214
245
{
215
246
return ( entities is IAsyncEnumerable < TEntity > )
216
247
? await entities . CountAsync ( )
217
248
: entities . Count ( ) ;
218
249
}
219
250
220
- /// </ inheritdoc>
251
+ /// <inheritdoc / >
221
252
public async Task < TEntity > FirstOrDefaultAsync ( IQueryable < TEntity > entities )
222
253
{
223
254
return ( entities is IAsyncEnumerable < TEntity > )
224
255
? await entities . FirstOrDefaultAsync ( )
225
256
: entities . FirstOrDefault ( ) ;
226
257
}
227
258
228
- /// </ inheritdoc>
259
+ /// <inheritdoc / >
229
260
public async Task < IReadOnlyList < TEntity > > ToListAsync ( IQueryable < TEntity > entities )
230
261
{
231
262
return ( entities is IAsyncEnumerable < TEntity > )
0 commit comments